Bootloader in C won't compile

Dnyanesh Gate picture Dnyanesh Gate · Aug 16, 2011 · Viewed 33.9k times · Source

I am a newbie in writing bootloaders. I have written a helloworld bootloader in asm, and I am now trying to write one in C. I have written a helloworld bootloader in C, but I cannot compile it.

This is my code. What am I doing wrong? Why won't it compile?

void print_char();
int main(void){
char *MSG = "Hello World!";
int i;

__asm__(
    "mov %0, %%SI;"
    :
    :"g"(MSG)
);
for(i=0;i<12;i++){
    __asm__(
        "mov %0, %%AL;"
        :
        :"g"(MSG[i])
    );
    print_char();
}

return 0;
}

void print_char(){
__asm__(
    "mov $0X0E, %AH;"
    "mov $0x00, %BH;"
    "mov $0x04, %BL;"
    "int $0x10"
);
}

Answer

dc0d32 picture dc0d32 · May 23, 2012

Let me assume a lot of things here: you want to run your bootloader on an x86 system, you have the gcc toolchain set up on a *nix box.

There are some points to be taken into account when writing a bootloader:

  1. the 510 byte limit for a VBR, even lesser for MBR due to partition table (if your system needs one)
  2. real mode - 16 bit registers and seg:off addressing
  3. bootloader must be flat binary that must be linked to run at physical address 7c00h
  4. no external 'library' references (duh!)

now if you want gcc to output such a binary, you need to play some tricks with it.

  1. gcc by default splits out 32bit code. To have gcc output code that would run in real mode, add __asm__(".code16gcc\n") at the top of each C file.
  2. gcc outputs compiled objects in ELF. We need a bin that is statically linked at 7c00h. Create a file linker.ld with following contents

    ENTRY(main);
    SECTIONS
    {    
        . = 0x7C00;    
        .text : AT(0x7C00)
        {
            _text = .;
            *(.text);
            _text_end = .;
        }
        .data :
        {
            _data = .;
            *(.bss);
            *(.bss*);
            *(.data);
            *(.rodata*);
            *(COMMON)
            _data_end = .;
        }    
        .sig : AT(0x7DFE)    
        {        
            SHORT(0xaa55);
        }    
        /DISCARD/ :
        {
            *(.note*);
            *(.iplt*);
            *(.igot*);
            *(.rel*);
            *(.comment);
            /* add any unwanted sections spewed out by your version of gcc and flags here */    
        }
    }
    
  3. write your bootloader code in bootloader.c and build the bootloader

    $ gcc -c -g -Os -march=i686 -ffreestanding -Wall -Werror -I. -o bootloader.o bootloader.c
    $ ld -static -Tlinker.ld -nostdlib --nmagic -o bootloader.elf bootloader.o
    $ objcopy -O binary bootloader.elf bootloader.bin
    
  4. Since you already have built boot loaders with ASM, I guess the rest is obvious to you.

- taken from my blog: http://dc0d32.blogspot.in/2010/06/real-mode-in-c-with-gcc-writing.html