Page 1 of 1
Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 2:20 pm
by Geometrian
Hi,
I have a very basic working kernel written in C that can print stuff.
I noticed that I cannot declare global variables without the kernel not running. I find this very odd. I thought
this might be related, so I link into an ELF, and then use objcopy. The kernel still works, but as soon as I declare a global variable, it doesn't.
Here's my compilation:
Code: Select all
nasm -f elf32 MOSS/kernel/jump.asm -o jump.o
gcc -c -Wall -Wextra -Werror -nostdlib -fno-builtin -nostartfiles -nodefaultlibs -nostdinc -ffreestanding MOSS/kernel/kernel.c -o kernel.o
ld --entry jump jump.o kernel.o -o jump_kernel.elf
objcopy -O binary jump_kernel.elf kernel.bin
Minimal sample:
Code: Select all
;jump.asm
[BITS 32]
[global jump]
[extern kernel_main]
jump:
call kernel_main
Code: Select all
//kernel.c
//static unsigned char* video = (unsigned char*)(0x00B8000); //uncomment this to see problem
void kernel_main(void) {
unsigned char* video2 = (unsigned char*)(0x00B8000);
video2[0] = 'H';
video2[1] = 0x07;
video2[2] = 'i';
video2[3] = 0x07;
HANG: goto HANG;
}
EDIT: the same occurs with function-scope static variables.
Thanks,
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 2:28 pm
by bluemoon
Geometrian wrote:The kernel still works, but as soon as I declare a global variable, it doesn't.
How that doesn't work? Do it link successfully? Is grub(or your boot loader) refuse to load it? or it loaded and crash at some point?
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 2:35 pm
by Geometrian
bluemoon wrote:How that doesn't work? Do it link successfully? Is grub(or your boot loader) refuse to load it? or it loaded and crash at some point?
It basically just sits at the bootloader. As far as I can tell, it doesn't execute anything. Maybe it's jmp-ing to a nop?
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 6:54 pm
by Geometrian
I think it's modifying the location of the entry point somehow, so that the hardcoded jump in the bootloader doesn't function. How can I explicitly set the linker to compensate for the extra data?
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 7:19 pm
by gerryg400
Geometrian wrote:I think it's modifying the location of the entry point somehow, so that the hardcoded jump in the bootloader doesn't function. How can I explicitly set the linker to compensate for the extra data?
When you convert the ELF file to a flat binary you are removing all the extra information that an ELF file contains. e.g. the entry point. Once you take that information away there is no way for a loader to know where to enter the binary.
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 7:47 pm
by Geometrian
gerryg400 wrote:When you convert the ELF file to a flat binary you are removing all the extra information that an ELF file contains. e.g. the entry point. Once you take that information away there is no way for a loader to know where to enter the binary.
. . . which is why the entry point needs to be at a particular place. I have had improved success with using the linker option "-Ttext 0x1000" or using the linker.ld script given on the
C++ Bare Bones page, but the kernel still runs incorrectly when using some things (notably arrays and static variables), and I have a hunch that global int variables working is basically chance.
This is exactly my problem, but no helpful answer.
Thanks,
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 7:52 pm
by gerryg400
The best thing to do is to disassemble the binary and see where the linker is putting things. You should be able to identify the text, data and rodata sections by inspection. That way you can quantify your experiments and see what exactly is going on.
Did you write your own loader ? In this case it's probably helpful if you did so that you can understand what it's doing.
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 8:17 pm
by bluemoon
This is a sign of relocation error - your code does not agree with where it is loaded, it's probably best to user a debugger to see where exactly the cpu is trying to access for the global variables.
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 10:15 pm
by Geometrian
After disassembling the kernel, it's clear that the first code point is actually a function that draws a pixel. The actual code for the main function doesn't come until after.
How should I resolve that--when I compile the kernel or when I link it? Or should I resolve it by trying to put the kernel's main function first?
Thanks,
Re: Global/static Variable in Flat Binary
Posted: Mon Nov 26, 2012 11:29 pm
by bewing
Yes, the third way -- for a flat binary executable, you always want the entrypoint to be at the very beginning. Which means that when you compile and link, the sourcefile that contains the entrypoint has to be first in the list, and the function that is your entrypoint must be the first function in your sourcefile.
Re: Global/static Variable in Flat Binary
Posted: Tue Nov 27, 2012 1:00 am
by Geometrian
Okay, I've rearranged the file. I think that helps the problem. The disassembly looks right for sure: the jump starts at 0x1000, and jumps to the kernel's main function at 0x1008.
However, I'm noticing that the data within global arrays appears to be all zero. Locally declared arrays mostly seem to work.
Re: Global/static Variable in Flat Binary
Posted: Tue Nov 27, 2012 7:36 am
by bewing
There really is no such thing as a globally defined variable in a flat binary. To have the compiler define a shared memory address you need to have symbols, and a flat binary has none -- that's basically the point of a flat binary. You need to allocate all your memory dynamically, or to use only known (hardcoded) memory addresses.
Re: Global/static Variable in Flat Binary
Posted: Tue Nov 27, 2012 7:40 am
by Combuster
I posted a wall of text back at SO for people's future reference. And the answer still applies to you.
At any rate, putting text at 0x1000 means a custom bootloader. Where does your data, read-only data and bss section end up in the binary? Where do they end up in physical RAM? What addresses are being used to access these sections? This problem is not fixed using guesswork, but you should already know the rough answers to these questions before you even run any assembler or compiler, so you can check that they did what you want them to do - not the other way around.
@bewing: I believe we're still talking about static content here, not dynamically loaded content. The symbols are available up to the linking process.
Re: Global/static Variable in Flat Binary
Posted: Wed Nov 28, 2012 12:15 pm
by Geometrian
The main problem seems to have been that the sector with the data wasn't being loaded by the bootloader--that combined with a number of bugs I have fixed. I am pleased to report that I can now print to the screen with a custom font, and use global variables and classes.
Thanks all!
Re: Global/static Variable in Flat Binary
Posted: Fri Dec 07, 2012 11:23 pm
by ranok
I find the best way to arrange the kernel, especially when it gets more complex is to use linker scripts, that way you can define entry points, where you want the various sections placed and linked together in the output flat binary. See
http://www.bravegnu.org/gnu-eprog/lds.html or the
wiki for more help in this area.