Page 1 of 5
Text output; pointer problems
Posted: Sun Mar 18, 2007 7:00 pm
by neon
Hello everyone,
In addition to my previous problem (Posted in my other post),
I am also having pointer issues with C in my kernel.
I am currently using DJGPP.
I have a simple _putch() routine (Puts a character on screen),
and it works just fine.
I attempted to write a version of _printf(). At the moment, it litterally
does nothing:
Code: Select all
void _printf (const char* format, ...) {
}
Calling this function from main() causes my kernel to triple fault.
I know the most common solution to this problem is including .rodata
section in my linker script, but I have that..
Here is my linker script:
Code: Select all
ENTRY(__Stage2)
OUTPUT_FORMAT("binary")
SECTIONS
{
.text 0x1000 :
{
code = .; _code = .; __code = .;
*(.text)
*(.rodata*)
. = ALIGN(4096);
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
Thanks for any help!
(Im just trying to get text on the screen!!)
Posted: Sun Mar 18, 2007 7:48 pm
by neon
Adding -fwritable-strings to gcc seems to have fixed the triple fault, but
nothing is being printed...
Code: Select all
void main () {
_clrscr (WINCOL);
_putch ('M'); // works
_printf ("H"); // Nothing is printed
__asm ("hlt");
}
void _printf (const char* format, ...) {
_putch (*format);
}
Posted: Mon Mar 19, 2007 3:59 am
by pcmattman
Ummm... correct me if I'm wrong but isn't .rodata meant to be in either the BSS or DATA sections?
Also I'd suggest that you don't start with a 'printf' until you have a working va_list (or some other form of retrieving an unknown number of arguments).
My text output routines started with 'kputc' (this was way back before I even thought about what I have now
), then 'kputs', then after a lot of time, 'printf' (I never got around to implementing kprintf, probably because printf's character output routine is kputc - so there's no real difference between the two).
Posted: Mon Mar 19, 2007 5:43 am
by Combuster
<standard_reply>Try using Bochs' Debugger</standard_reply>
@pcmattman
.rodata is in the .text section because its read-only. putting it in .data is ok but less secure, putting it in .bss is an invitation for confusion and related problems.
Posted: Mon Mar 19, 2007 7:09 am
by os64dev
Combuster wrote:@pcmattman
.rodata is in the .text section because its read-only. putting it in .data is ok but less secure, putting it in .bss is an invitation for confusion and related problems.
putting it in .bss is kinda dumb because it is unintialised data and a string is always initialised. ok, now for the .text section. if i put machine code in a read only string. putting the rodata in a text section means that i can execute my machine code because it is located in a code segment. if i however put the string in the .data section and seperate the data section in a read-only and read/write part (on page alignment) i can protect the string by for instance the NX bit rendering the machine code useless.
conclusion imho .data is the only correct location for .rodata.
Posted: Mon Mar 19, 2007 7:18 am
by urxae
This may be a stupid question, but why not put .rodata in, you know, .rodata?
That way you can mark it as non-executable and read-only.
That's what I do, anyway...
Posted: Mon Mar 19, 2007 11:12 am
by salil_bhagurkar
Try removing the '...' from the _printf function. When you are not using va_list then you should try the following function:
Code: Select all
void _printf(const char *format)
{
_putch(*format);
}
Posted: Mon Mar 19, 2007 5:00 pm
by neon
I put *(.rodata*) in the .data section, but it still prints nothng.
I also put *(.rodata*) in its own section, still nothing.
Here is my _printf that I used:
Code: Select all
void _printf (const char* format) {
_putch (*format);
}
My new linker script (with .rodata section):
Code: Select all
ENTRY(__Stage2)
OUTPUT_FORMAT("binary")
SECTIONS
{
.text 0x1000 :
{
code = .; _code = .; __code = .;
*(.text)
. = ALIGN(4096);
}
.data :
{
data = .; _data = .; __data = .;
*(.data)
. = ALIGN(4096);
}
.rodata :
{
rodata = .; _rodata = .; __rodata = .;
*(.rodata*)
. = ALIGN(4096);
}
.bss :
{
bss = .; _bss = .; __bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .; _end = .; __end = .;
}
Any more suggestions?
Im going to run it through the debugger and see if I can find anything...
Posted: Mon Mar 19, 2007 5:17 pm
by Brynet-Inc
Man all those underscores are ugly..
Posted: Mon Mar 19, 2007 6:39 pm
by neon
Im officialy confused o.0:
My linker is loading my kernel from address 0x18f8, but it is supposed
to be 0x1000. (Please see my other post for the warning from the linker
I get...)
I used objdump to disassemble it:
Code: Select all
Disassembly of section .text:
//My linker loads kernel at 0x18f8--beginning here, but I cant
// get objdump to disassemble it..
000018f8 <_main-0x8>:
...
00001900 <_main>:
1900: 55 push %ebp
1901: 89 e5 mov %esp,%ebp
1903: 83 ec 08 sub $0x8,%esp
1906: 83 e4 f0 and $0xfffffff0,%esp
1909: b8 00 00 00 00 mov $0x0,%eax
190e: 29 c4 sub %eax,%esp
1910: 83 ec 0c sub $0xc,%esp
1913: 6a 1f push $0x1f
1915: e8 22 00 00 00 call 193c <__clrscr>
191a: 83 c4 10 add $0x10,%esp
191d: 83 ec 0c sub $0xc,%esp
// Here we push address 0x2008 on the stack, containing our string
// we want _printf to output. We call printf...
1920: 68 08 20 00 00 push $0x2008
1925: e8 0e 01 00 00 call 1a38 <__printf>
192a: 83 c4 10 add $0x10,%esp
192d: f4 hlt
192e: c9 leave
192f: c3 ret
Printf:
Code: Select all
00001a38 <__printf>:
1a38: 55 push %ebp
1a39: 89 e5 mov %esp,%ebp
1a3b: 83 ec 08 sub $0x8,%esp
1a3e: 83 ec 0c sub $0xc,%esp
1a41: 8b 45 08 mov 0x8(%ebp),%eax
1a44: 0f be 00 movsbl (%eax),%eax
1a47: 50 push %eax
1a48: e8 49 ff ff ff call 1996 <__putch>
1a4d: 83 c4 10 add $0x10,%esp
1a50: c9 leave
1a51: c3 ret
The important lines from main():
Code: Select all
// Here we push address 0x2008 on the stack, containing our string
// we want _printf to output. We call printf...
1920: 68 08 20 00 00 push $0x2008
1925: e8 0e 01 00 00 call 1a38 <__printf>
Notice we push address 0x2008 on the stack. What is at this
address...? :
Code: Select all
Disassembly of section .data:
00002000 <djgpp_first_ctor>:
2000: 00 00 add %al,(%eax)
...
00002004 <__yPos>:
2004: 00 00 add %al,(%eax)
...
00002008 <LC0>:
2008: 48 dec %eax <<<<< My "H"
2009: 00 00 add %al,(%eax)
The value 0x48! Which translates to the ASCII character H!
(The character I am trying to print as a string)
...Yet _printf still prints null...
Any more ideas..?
Posted: Mon Mar 19, 2007 10:13 pm
by neon
Just want to add:
Code: Select all
void _printf (const char* format) {
_putch (*format); //prints nothing
//_putch ('A'); // works
}
At first I was suspecting a stack problem, but nonpointer
parameters work just fine..
Posted: Mon Mar 19, 2007 11:44 pm
by pcmattman
Have you tried it without the 'const'? The parameters don't have to be constant, it just helps you make sure that you don't overwrite them later. Try removing the 'const' and see if it fixes the problem.
Posted: Tue Mar 20, 2007 1:47 am
by os64dev
can we see the code for putch because if you print it in the same foreground as background color you will not see it, though it has been printed.
Posted: Tue Mar 20, 2007 5:03 pm
by neon
I took the const out, but still doesnt work (Same problem--prints nothing)
Heres my _putch:
Code: Select all
#define VIDMEM 0xB8000 // video memory
#define COLS 80 // width and height
#define LINES 24
#define ATTRIB 0x1F
#define WINCOL 0x1F // Window color
static int _xPos=0; // current position
static int _yPos=0;
void _putch (int c) {
unsigned char* vmem = (unsigned char*)VIDMEM;
//watch for newline
if (c=='\n' || c=='\r') {
_xPos=0;
_yPos++;
if (_yPos>LINES)
_yPos=0;
return;
}
// write the character
*(vmem + (_xPos + _yPos * COLS) *2) = c & 0xFF;
*(vmem + (_xPos + _yPos * COLS) *2+1) = ATTRIB;
// watch for end of line
if (_xPos++ >COLS)
_putch ('\n');
}
All of the characters use 0x1f for its attribute (Which is yellow text on
blue background)
(I was really thinking taking const out would fix it...)
Any more suggestions,,,>
I confused at what the prolem could be...
Posted: Tue Mar 20, 2007 5:08 pm
by Alboin
Instead of:
Code: Select all
*(vmem + (_xPos + _yPos * COLS) *2) = c & 0xFF;
*(vmem + (_xPos + _yPos * COLS) *2+1) = ATTRIB;
Try:
Code: Select all
vmem[(_xPos + _yPos * COLS) *2)] = c & 0xFF;
vmem[(_xPos + _yPos * COLS) *2+1)] = ATTRIB;
I think it's equivalent, actually...but, why not try it? It's what I use in my kernel, and it works nicely...
Edit: And why is c an int? Just use a char, and you can save yourself the trouble of writing