在C中写入Bootloader

时间:2011-08-16 14:31:54

标签: c linux gcc assembly bootloader

我是编写bootloaders的新手。我在asm写了一个helloworld bootloader,并且 我现在正在尝试在C中编写一个。我在C中编写了一个helloworld引导程序,但我无法编译它。

这是我的代码。我究竟做错了什么?我完全采取了错误的做法吗?

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"
);
}

6 个答案:

答案 0 :(得分:15)

我建议您查看http://wiki.osdev.org/Rolling_Your_Own_Bootloader以及http://www.brokenthorn.com/Resources/OSDevIndex.html

的Bootloader部分

有一些很好的教程可以帮助您自己开始自己的引导加载程序。如果您需要更多信息,也可以加入freenode中的#osdev频道加入讨论。

答案 1 :(得分:11)

让我在这里假设很多东西:你想在x86系统上运行你的bootloader,你在* nix框上设置了gcc工具链。

编写引导加载程序时需要考虑以下几点:

  1. VBR的510字节限制,由于分区表(如果您的系统需要一个),MBR甚至更小
  2. 实模式 - 16位寄存器和seg:off寻址
  3. bootloader必须是平面二进制文件,必须链接到物理地址7c00h
  4. 没有外部图书馆&#39;参考文献(duh!)
  5. 现在如果你想让gcc输出这样的二进制文件,你需要用它来玩一些技巧。

    1. gcc默认情况下会拆分32位代码。要获得可在实模式下运行的gcc输出代码,请在每个C文件的顶部添加__asm__(".code16gcc\n")
    2. gcc在ELF中输出编译对象。我们需要一个在7c00h静态链接的bin。创建一个包含以下内容的文件linker.ld

      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. bootloader.c中编写引导加载程序代码并构建引导加载程序

      $ 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. 由于您已经使用ASM构建了引导加载程序,我想其余部分对您来说很明显。

    5. - 取自我的博客:http://dc0d32.blogspot.in/2010/06/real-mode-in-c-with-gcc-writing.html

答案 2 :(得分:5)

引导加载程序是用ASM编写的。

编译C代码(或C ++或其他)时,编译器会将您的人类可读代码“转换”为机器代码。所以你不能确定结果。

当PC启动时,BIOS将从特定地址执行代码。 该代码需要直接执行。

这就是你使用汇编的原因。 这是处理器执行未编辑代码的唯一方法。

如果你想用C编码,你仍然需要编写一个ASM引导程序代码,它将负责正确加载你使用的编译器生成的机器代码。

您需要了解每个编译器将生成不同的机器代码,可能需要在执行前进行预处理。

BIOS不允许您预处理机器代码。 PC启动只是跳转到内存位置,这意味着位于此位置的机器代码将直接执行。

答案 3 :(得分:2)

由于您使用的是GCC,因此您应该阅读有关不同“目标环境”的信息页面。您最有可能想要使用 -ffreestanding 标志。此外,我不得不使用 -fno-stack-protector 标志来避免编译器的一些难看的魔法。

然后,您将收到链接器错误,指出未找到 memset 等。因此,您应该实现自己的这些版本并将它们链接起来。

答案 4 :(得分:1)

几年前我试过这个 - 选项可能已经改变了。

您必须使用gcc运行-ffreestanding(请勿关联),然后使用ld与标记-static-nostdlib

答案 5 :(得分:-2)

据我所知,您不能用C编写Bootloader。这是因为,C需要您在32位保护模式下工作,而在Bootloader中某些部分处于16位模式。