Page 1 of 1
Easy question for C people :).
Posted: Sun Sep 17, 2006 2:15 pm
by mrkaktus
Hi, I'm trying to write simple program in C for my OS and I need to compile it to BIN (binary) format. I prefer ASM but I understand that most of people would like to use C
so I need to know how to do that.
hello.c :
void main (void)
{
asm ("movl $0xB80A0, %edi");
for (;;)
{
asm ("movl $' ', (%edi)");
asm ("movl $'2', (%edi)");
}
}
This is simple C program that will show all the time 2/space on the first place in second row on the screen. (He gets rights to write directly to screen area for tests only
).
I'm using DJGPP under WinXP, and I'm trying to compile it in such way:
D:\DJGPP\bin>gcc -c hello.c -o hello.o
hello.c: In function 'main':
hello.c:2: warning: return type of 'main' is not 'int'
D:\DJGPP\bin>ld --oformat binary hello.o -o hello.bin
d:/djgpp/bin/ld.exe: warning: cannot find entry symbol start; defaulting to 00001000
And when I'm putting created bin file to execute in my OS it crashes with GPF (0x13). So I understand that something is wrong with linking but I don't know how to compile it properly.
Please help
.
EDIT:
Ok, I figured it out
. Now I'm playing with C apps
. No help neded, moderator can delete this topic
.
Posted: Sun Sep 17, 2006 6:56 pm
by SpooK
I would suggest not deleting the topic. It helps out when people are searching the forum database for answers.
An answer is an answer, even if it answers your own question
Re: Easy question for C people :).
Posted: Wed Jan 03, 2007 4:10 pm
by Scalpel
mrkaktus wrote:
D:\DJGPP\bin>ld --oformat binary hello.o -o hello.bin
d:/djgpp/bin/ld.exe: warning: cannot find entry symbol start; defaulting to 00001000
Ok, I figured it out
.
What did you do to fix it?? I have the same problem. I'm, trying to, use Windows XP/DJGPP as well to build my C++ kernel. When I boot the image in VMWare the virtual machine just keeps on rebooting.
Posted: Wed Jan 03, 2007 8:19 pm
by Daedalus
As a general rule, please post your findings when you figure something out - it helps others, and would help the guy above me
Posted: Thu Jan 04, 2007 5:06 am
by Ready4Dis
It was defaulting to a location for linking, it wasn't the same location he was loading it at in his OS, please make sure if you load your binary file at 0x1000000 that it is linked as such, or is linked to a non-flat file that has a relocation table that you can runtime-link.
Posted: Thu Jan 04, 2007 12:24 pm
by Scalpel
So the problem is in the linker script then?
My link.ld script looks like this:
Code: Select all
OUTPUT_FORMAT("binary")
ENTRY(start)
SECTIONS
{
.text 0x10000:
{
code = .;
_code = .;
__code = .;
*(.text)
. = ALIGN(4096);
}
.rodata :
{
rodata = .;
_rodata = .;
__rodata = .;
*(.rodata)
. = ALIGN(4096);
}
.data :
{
data = .;
_data = .;
__data = .;
*(.data)
. = ALIGN(4096);
}
.bss :
{
bss = .;
_bss = .;
__bss = .;
*(.bss)
. = ALIGN(4096);
}
end = .;
_end = .;
__end = .;
}
Is it the address in the .text section (which in my script is set to 0x10000) which is wrong then? What determines what that address should be?
The linker script I'm using have been written from tutorials I've read. Are there any good resources where I can read more about what the different sections in the linker script actually means?
Posted: Thu Jan 04, 2007 12:59 pm
by Ready4Dis
That does look ok, I don't align my sections on 4096 though, would make my kernel much larger than required. Anyways, where does your boot sector load your kernel at? Is 0x10000 a valid location, that looks ok to me, it will start running at 0x10000 though, so if you have data defined at the top, it will try running this rather than your code! Since you are outputing to a binary file, you don't even need to define start, because it will always start at that point in memory, make sure you have a jump as the first command, or any variables you define at the bottom. Not sure why it says defaulting to 00001000, if you are telling it 0x10000 that is off by a 0
. If that's a typo, then disregard, lol. These 2 locations should be identical though, if not something is wrong.
One last thing, if you are doing it in straight C, you would normally have an ASM stub program that would just jump to your c_main function, most compilers output a relocation table, which would tell whatever os that this is the entry point (pointer to main), so the os would automagically jump there. If you output to a binary file, it loses this table, and the pointer to your main function, so you must either a.) provide a way to store this poitner in a known location so you can jump to it, or B create a stub asm program that jumps to the main as the first instruction to make sure it doesn't try to run any variables![/img]
Posted: Thu Jan 04, 2007 1:23 pm
by gaf
Provided that you're still using John Fines bootsector the start-up process should be as folllows:
John Fine wrote:01 ) Enables the A20 gate.
02 ) Switches to big real mode
03 ) Computes the locations of the FAT, the root directory and the first cluster.
04 ) Reads in the root directory
05 ) Scans the root directory for a specific file (KERNEL.BIN in the example)
06 ) Reads in the FAT
07 ) Reads the file (KERNEL.BIN) to RAM starting at physical 1Mb.
08 ) Builds two page tables and one page directory mapping:
a) The first 4Mb linear to the first 4Mb physical
b) Linear FF800000 (where all my protected mode images start) to physical RAM starting at 1Mb
c) Self map the page directory to the end of linear memory
09 ) Switch to protected mode with paging turned on
10 ) JMP to KERNEL.BIN at linear FF800000
Having loaded your kernel the bootloader jumps to 0xFF800000 to start the operating system. In order to make variables and jumps function properly your kernel must be linked to the same address.
cheers,
gaf
Posted: Thu Jan 04, 2007 1:26 pm
by Scalpel
Ready4Dis wrote:That does look ok, I don't align my sections on 4096 though, would make my kernel much larger than required.
What do you do then?
Ready4Dis wrote:Anyways, where does your boot sector load your kernel at?
Ah, that's it! I'm using John Fine's bootf02. It loads a kernel from 0xFF800000. I changed the address in my link.ld script to this, and that worked! The warning still comes when i link, but now I am able to boot into the kernel.
Ready4Dis wrote:Not sure why it says defaulting to 00001000, if you are telling it 0x10000 that is off by a 0
. If that's a typo, then disregard, lol. These 2 locations should be identical though, if not something is wrong.
Typo!
Ready4Dis wrote:One last thing, if you are doing it in straight C, you would normally have an ASM stub program that would just jump to your c_main function......
I'm writing (or at least trying) the kernel in C++. I have a loader.asm script like this:
Code: Select all
[BITS 32] ;protected mode
[global start]
[extern _main]
start:
call _main
cli
hlt
which calls my main-function from my kernel.cpp.
Posted: Thu Jan 04, 2007 1:49 pm
by Scalpel
Let me see if I'm understanding this correctly.
1. bootf02 is filling the first 512 bytes of my image file, and is ended by 55AA, and thus is interpreted as a bootable disk.
2. bootf02 does it's magic with A20, memory and such.
3. The bootloader jumps to 0xFF800000, which is where my code begins.
4. In my linker script I've stated that
is the absolute beginning of my code.
5. In my loader.asm file I have a few definitions at the top, but start: is the first step run by my code. The first CPU instruction run by my code is "call _main".
6. During linking with ld, for some reason, it doesn't find the entry point called start, but since I'm using .text 0xFF800000 in my linker script it defaults to the correct address anyway.
Is it possible to use a tool to examine my .img file with a disassembler tool, and observe that "call _main" is located at 0xFF800000, or is this address only used during the actual booting process?
Hope you bear with me. I'm trying to wrap my head around this.
Posted: Thu Jan 04, 2007 3:56 pm
by INF1n1t
Hm, the boot loader is loaded at 0x7c00. If they thought, the boot loader must be loaded in 0x8c00, it would be executing there. You can tell the linker however, where the code would be running, so it could make the right addressing for that...I've debugger several programs with ollydbg and saw that the programs are using base address+offset or just address linked correctly...
So, if you load your code at 0xFF8000....it will run there. If not, then it won't run there. You must tell the linker the code will run at 0xFF80000...so it could create the right addresses.
For example, the file has several instructions:
Just an example. The compiler would generate (at least I think so) instructions like:
For example. Then you tell the linker, you want to set up the code for address 'x'. So, the linker will take the addresses and add x to them and generate the output code...
Sorry, if I'm not correct at these, but I'm not talking from experience, I'm talking from logic!
Posted: Thu Jan 04, 2007 4:23 pm
by Ready4Dis
Scalpel wrote:Let me see if I'm understanding this correctly.
1. bootf02 is filling the first 512 bytes of my image file, and is ended by 55AA, and thus is interpreted as a bootable disk.
2. bootf02 does it's magic with A20, memory and such.
3. The bootloader jumps to 0xFF800000, which is where my code begins.
4. In my linker script I've stated that
is the absolute beginning of my code.
5. In my loader.asm file I have a few definitions at the top, but start: is the first step run by my code. The first CPU instruction run by my code is "call _main".
6. During linking with ld, for some reason, it doesn't find the entry point called start, but since I'm using .text 0xFF800000 in my linker script it defaults to the correct address anyway.
Is it possible to use a tool to examine my .img file with a disassembler tool, and observe that "call _main" is located at 0xFF800000, or is this address only used during the actual booting process?
Hope you bear with me. I'm trying to wrap my head around this.
Yes, use a hex editor, you should see a short or far jump (depending on how far the jump is, which depends on how much assembly and C end up between the jump and your main function). Also, I use no underscores (there is an option in GCC for this, makes it much simpler for me to remember variable names!) You have start set as global, so that is good, not sure why it can't find, it, but I had a similar problem, can't remember how I fixed it, can check my script when i go home tomorrow. It's not important, you can disregard it anyways, because once you compile to binary, it loses that type of information anyways, so it's not important
. I don't align my segments on a 4096 boundary, the reason some people do this, is so they can keep data and code seperate, you can allocate data sections as read/write, and the code section as read only, this stops self modifying code from working, and can be a bit safer I guess, but I am not worried about it much, and my kernel needs to self modify itself, so not a big deal! Also, if you enable PAE, and are using 64k blocks, you would have to align on a 64k boundary, which means tons of wasted space for a smaller kernel/app. Also, unless you have a method to tell your boot loader how much of a BSS you require, put that section BEFORE the data section, this ensures that your BSS is actually in your binary flat file, so you don't have to allocate it after you load the kernel (unless you feel like it, that is fine, and if you have a very large BSS it'd be worth it to store it's size, and add that after the kernel is loaded from disk, and ZERO IT OUT!!). Anyways, hope this helps, let me know if you need more help, I have mine working pretty good and have a pretty good grasp on what's going on I think
.
Posted: Fri Jan 05, 2007 10:18 am
by gaf
Scalpel wrote:During linking with ld, for some reason, it doesn't find the entry point called start, but since I'm using .text 0xFF800000 in my linker script it defaults to the correct address anyway.
With DJGPP you might have to add an underscore to your start label in loader.asm
Code: Select all
[BITS 32] ;protected mode
[global _start]
[extern _main]
_start:
call _main
cli
hlt
INF1n1t wrote:Then you tell the linker, you want to set up the code for address 'x'. So, the linker will take the addresses and add x to them and generate the output code...
That's the idea
. The compiler creates symbols for variables and functions relative to the beginning of the executable. By setting an offset you tell the linker where the binary will be loaded, so that the addresses defined in the object files can be made absolute.
Ready4Dis wrote:Yes, use a hex editor, you should see a short or far jump.
It's probably much easier to see the effect using a disassembler. GCC already comes with objdump, which should be sufficient to do the job:
Code: Select all
objdump -D --architecture=i386 --target=binary kernel.bin
Looking at the disassembly you should now see that the image starts with your assembler loader. If you locate an absolute jump you can also observe what effect the offset declared in the linker-script has on your code (just change it a few times).
cheers,
gaf