Linux C 中的引导加载程序将无法编译

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7079866/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 05:44:06  来源:igfitidea点击:

Bootloader in C won't compile

clinuxgccassemblybootloader

提问by Dnyanesh Gate

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.

我是编写引导加载程序的新手。我已经用 asm 编写了一个 helloworld 引导加载程序,现在我正在尝试用 C 编写一个。我已经用 C 编写了一个 helloworld 引导加载程序,但我无法编译它。

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 
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 */    
    }
}
X0E, %AH;" "mov
$ 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
x00, %BH;" "mov
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 */    
    }
}
x04, %BL;" "int
$ 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
x10" ); }

回答by Macmade

A bootloader is written in ASM.

引导加载程序是用 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.

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

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

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

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.

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

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.

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

回答by rodrigo

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

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

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

然后,您将收到链接器错误,提示未找到memset等。所以你应该实现你自己的这些版本并将它们链接起来。

回答by Foo Bah

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

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

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

您必须gcc使用-ffreestanding(don't link)运行,然后使用ld标志进行链接-static-nostdlib

回答by dc0d32

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.

让我在这里假设很多事情:你想在 x86 系统上运行你的引导加载程序,你在 *nix 框上设置了 gcc 工具链。

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!)
  1. VBR 的 510 字节限制,由于分区表的原因,MBR 甚至更少(如果您的系统需要一个)
  2. 实模式 - 16 位寄存器和 seg:off 寻址
  3. 引导加载程序必须是平面二进制文件,必须链接才能在物理地址 7c00h 上运行
  4. 没有外部“库”引用(废话!)

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

现在如果你想让 gcc 输出这样的二进制文件,你需要用它玩一些技巧。

  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.ldwith following contents

    ##代码##
  3. write your bootloader code in bootloader.cand build the bootloader

    ##代码##
  4. Since you already have built boot loaders with ASM, I guess the rest is obvious to you.

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

    ##代码##
  3. 写入引导加载程序代码bootloader.c并构建引导加载程序

    ##代码##
  4. 由于您已经使用 ASM 构建了引导加载程序,我想其余的对您来说是显而易见的。

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

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

回答by GoodNameHere

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.

据我所知,你不能用 C 编写引导加载程序。那是因为,C 需要你在 32 位保护模式下工作,而在引导加载程序中,某些部分处于 16 位模式。