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 :D), 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. :wink:

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

Code: Select all

c & 0xFF