I'm writing an x86 bootloader and I'm currently trying to make if enable protected mode and then jump into a main
function defined in a C file. But I am having problems linking the object files created from my assembly code and my C code.
Here's what my boot.asm
looks like (non-relevant parts omitted):
[bits 16]
[extern main]
; ...
lgdt [gdt_descriptor]
mov eax, cr0
or al, 0x1
mov cr0, eax
jmp GDT_SELECTOR_KERNEL_CODE:protected_mode_start
[bits 32]
protected_mode_start:
; ...
call main
Length and location of my GDT are stored at gdt_descriptor
and GDT_SELECTOR_KERNEL_CODE
is the kernel code segments offset in the GDT.
My C code in boot.c
currently just looks like:
int main(void)
{ return 0; }
I have written also the following linker script boot.ld
:
OUTPUT_FORMAT("elf32-i386");
ENTRY(_start);
/* TODO: inject definitions from Makefile */
SECTIONS
{
/* code */
. = 0x7C00;
.text : {
out/boot_asm.o(.text);
*(.text);
}
/* data */
.data : SUBALIGN(2) {
*(.data);
*(.rodata);
}
/* boot signature */
.sig 0x7DFE : {
SHORT(0xAA55);
}
}
And when trying to compile and link using nasm
, gcc
and ld
I get:
nasm -f elf32 -g -F dwarf -Wall -Werror -i asm asm/boot.asm -o out/boot_asm.o
gcc -m32 -fno-PIC -ffreestanding -nostdinc -Os -fomit-frame-pointer -g -gdwarf -Wall -Werror c/boot.c -o out/boot_c.o
ld -T ld/boot.ld -melf_i386 out/boot_asm.o out/boot_c.o -o out/boot.elf
ld: out/boot_asm.o: in function `protected_mode_start':
out/boot.asm:187: undefined reference to `main'
I have several questions here:
- Why do I get the "undefined reference error"
- If I don't define a "main" function in
boot.c
,gcc
won't create an object file at all, shouldn't this be possible with-ffreestanding
? - I am unsure how to set up BSS and the stack. Should the BSS segment simply occupy the remaining bytes from the end of the data segment to the end of the 512 bytes of the bootloader? Where do I set the stack pointer before
call main
? - Is the way I lay out code and data segment in my linker file compatible with my protected mode setup? I am confused as to what is what here because the binary I create runs both in 16 and in 32 bit mode.
ldr x1, =main_entry
,br x1
.void main_entry()
is function in main.c file to be called. – user3124812.bss (NOLOAD) : ALIGN(8) { *(.bss) *(.bss.*) }
. every 'bss' between{}
is on new line. – user3124812sp
orx30
for arm32/64) – user3124812c/boot.c
to an ELF executable called out/boot_c.o rather than an ELF object. Your GCC command line is missing the-c
option to compile the.c
file to a.o
object file. Possibly you are doing this but once you have the ELF executable you will need to convert it to binary with something likeobjcopy -O binary out/boot.elf out/boot.bin
– Michael Petch