String pointers off by 0x80 bytes in Protected Mode C code
Posted: Mon Oct 14, 2013 4:10 pm
First of all, hello everyone. I got into this entire OS deving thing a few weeks ago and finally got some time this weekend to read up on protected mode and start work on some test code to interface with the graphics hardware without the BIOS. I wrote a console library that prints to the VGA text buffer.
Writing individual fixed characters works, however, when I try to use my string printing function, like this:
I read garbage from memory.
Since I had some strings in my second stage bootloader, for example, at 0x80F, I tried passing that address to the string printing function, only to notice that the function read exactly 0x80 bytes AHEAD of where I want it to read! I observed later that this happened to ALL pointers in my C code, including the VGA text buffer pointer — even though I specified 0xB8000, I had to subtract 0x80 to be able to write to the character at (0, 0) in the buffer.
When simply appending "-0x80" after all addresses, pointers and so on, everything works flawlessly, but this seems like a really bad hack I shouldn't have to deal with. What might cause this problem? Here's how I compile and link my kernel:
This produces a flat binary as an output, with all my strings in it, and I can disassemble it with gobjtool fine and see code that roughly matches my C code.
In addition, I loaded this into QEMU and stepped through the code with gdb — my function gets the proper logical address, which, when I examine memory, contains my string, and when I subtract the offset to which the kernel is loaded also matches the location of the string in my flat binary, so I feel like I'm making some mistake with configuring the processor. My GDT is as follows, although I doubt it to be an issue as it's identical to the ones used by basically everyone else:
Thanks for any help… I'm sure I made some stupid mistake somewhere in here!
Writing individual fixed characters works, however, when I try to use my string printing function, like this:
Code: Select all
console_write_string("Hello, kernel world!\n");
Since I had some strings in my second stage bootloader, for example, at 0x80F, I tried passing that address to the string printing function, only to notice that the function read exactly 0x80 bytes AHEAD of where I want it to read! I observed later that this happened to ALL pointers in my C code, including the VGA text buffer pointer — even though I specified 0xB8000, I had to subtract 0x80 to be able to write to the character at (0, 0) in the buffer.
When simply appending "-0x80" after all addresses, pointers and so on, everything works flawlessly, but this seems like a really bad hack I shouldn't have to deal with. What might cause this problem? Here's how I compile and link my kernel:
Code: Select all
gcc -c -Os -Oz -arch i386 -g -Wmost -fno-builtin -static -fomit-frame-pointer -mpreferred-stack-boundary=2 -fno-align-functions -mno-sse2 -nostartfiles -nodefaultlibs -std=c99 -Wno-unused-variable -mfpmath=387 -fno-stack-protector -I. -ffreestanding *.c
gcc -static -Wl,-preload -Wl,-e,_loader -Wl,-segaddr,__TEXT,3000 -ffreestanding -nostdlib -arch i386 -o kernel.o -Wl,-segalign,20 *.o
gobjcopy -O binary kernel.o kernel.bin
In addition, I loaded this into QEMU and stepped through the code with gdb — my function gets the proper logical address, which, when I examine memory, contains my string, and when I subtract the offset to which the kernel is loaded also matches the location of the string in my flat binary, so I feel like I'm making some mistake with configuring the processor. My GDT is as follows, although I doubt it to be an issue as it's identical to the ones used by basically everyone else:
Code: Select all
608 gdt_start:
609 00000430 0000000000000000 dd $00, $00
610
611 ; Code segment
612 00000438 FFFF dw $0FFFF
613 0000043A 0000 dw $0000
614 0000043C 00 db $00
615 0000043D 9A db $9A
616 0000043E CF db $0CF
617 0000043F 00 db $00
618
619 ; Data segment
620 00000440 FFFF dw $0FFFF
621 00000442 0000 dw $0000
622 00000444 00 db $00
623 00000445 92 db $92
624 00000446 CF db $0CF
625 00000447 00 db $00