开发者

Bootloader in C won't compile

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 hellowo开发者_如何学编程rld 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"
);
}


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


A bootloader is written in ASM.

When compiling C code (or C++, or whatever), a compiler will 'transform' your human readable code into machine code. So you can't be sure about the result.

When a PC boots, the BIOS will execute code from a specific address. That code needs to be executable, directly.

That's why you'll use assembly. It's the only way to have un-altered code, that will be run as written, by the processor.

If you want to code in C, you'll still have to code an ASM bootloader, which will be in charge to load properly the machine code generated by the compiler you use.

You need to understand that each compiler will generate different machine codes, that may need pre-processing before execution.

The BIOS won't let you pre-process your machine code. The PC boot is just a jump to a memory location, meaning the machine code located at this location will be directly executed.


Since you are using GCC, you should read the info pages about the different "target environments". You most probably want to use the -ffreestanding flag. Also I had to use -fno-stack-protector flags to avoid some ugly magic of the compiler.

Then, you will get linker errors saying that memset and the like are not found. So you should implement your own version of these and link them in.


I tried this a few years ago -- options may have changed.

You have to run gcc with -ffreestanding (don't link) and then link using ld with the flags -static, -nostdlib


As far as I know, you cannot write bootloader in C. That is because, C needs you to work in a 32-bit protected mode while in bootloader some portions are in 16-bit mode.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜