在Linux中从C代码生成原始二进制文件

我一直在实现一个简单的x86架构操作系统。 我实现了从磁盘加载内核并以32位模式进入的引导加载程序的汇编代码。 加载的内核代码是用C编写的,所以为了执行这个想法就是从C代码生成原始二进制文件。

首先,我使用了这些命令:

$gcc -ffreestanding -c kernel.c -o kernel.o -m32 $ld -o kernel.bin -Ttext 0x1000 kernel.o --oformat binary -m elf_i386 

但是,它没有生成任何二进制回馈这些错误:

 kernel.o: In function 'main': kernel.c:(.text+0xc): undefined reference to '_GLOBAL_OFFSET_TABLE_' 

为了清楚起见,kernel.c代码是:

 /* kernel.c */ void main () { char *video_memory = (char *) 0xb8000 ; *video_memory = 'X'; } 

然后我遵循这个教程: http ://wiki.osdev.org/GCC_Cross-Compiler为我自己的目标实现我自己的交叉编译器。 它为我的目的工作,但是反汇编命令ndisasm我获得了这个代码:

 00000000 55 push ebp 00000001 89E5 mov ebp,esp 00000003 83EC10 sub esp,byte +0x10 00000006 C745FC00800B00 mov dword [ebp-0x4],0xb8000 0000000D 8B45FC mov eax,[ebp-0x4] 00000010 C60058 mov byte [eax],0x58 00000013 90 nop 00000014 C9 leave 00000015 C3 ret 00000016 0000 add [eax],al 00000018 1400 adc al,0x0 0000001A 0000 add [eax],al 0000001C 0000 add [eax],al 0000001E 0000 add [eax],al 00000020 017A52 add [edx+0x52],edi 00000023 0001 add [ecx],al 00000025 7C08 jl 0x2f 00000027 011B add [ebx],ebx 00000029 0C04 or al,0x4 0000002B 0488 add al,0x88 0000002D 0100 add [eax],eax 0000002F 001C00 add [eax+eax],bl 00000032 0000 add [eax],al 00000034 1C00 sbb al,0x0 00000036 0000 add [eax],al 00000038 C8FFFFFF enter 0xffff,0xff 0000003C 16 push ss 0000003D 0000 add [eax],al 0000003F 0000 add [eax],al 00000041 41 inc ecx 00000042 0E push cs 00000043 088502420D05 or [ebp+0x50d4202],al 00000049 52 push edx 0000004A C50C04 lds ecx,[esp+eax] 0000004D 0400 add al,0x0 0000004F 00 db 0x00 

正如你所看到的,前9行(除了不知道为什么插入的NOP)是我主函数的汇编翻译。 从10行到最后,有很多代码我不知道为什么在这里。

最后,我有两个问题:

1)为什么生成这个代码?

2)有没有办法从C生产原始机器码没有这些无用的东西?

首先有几点提示:

  • 避免将你的启动例程命名为main 。 这是混淆(无论是为读者,也可能是为编译器;当你不通过-ffreestandinggcc-ffreestanding它是处理main非常具体)。 使用其他的东西,如startbegin_of_my_kernel

  • gcc -v编译来理解你的特定编译器在做什么。

  • 你可能应该问你的编译器进行一些优化和所有的警告,所以把-O -Wall至少传给gcc

  • 你可能需要查看生成的汇编代码,所以使用gcc -S -O -Wall -fverbose-asm kernel.c来获取kernel.s汇编程序文件,并查看它

  • 正如迈克尔·佩奇 ( Michael Petch)评论的那样,你可能想通过-fno-exceptions

  • 你可能需要一些链接描述文件和/或一些手写的crt0汇编程序

  • 你应该读一些关于链接器和装载器的东西


  kernel.c:(.text+0xc): undefined reference to '_GLOBAL_OFFSET_TABLE_' 

这闻起来像一些与位置无关的代码 。 我的猜测是:尝试编译一个明确的 -fno-pic-fno-pie

(在某些 Linux发行版上,它们的gcc 可能会配置一些-fpic启用的-fpic

PS。 如果您需要x86 32位二进制文​​件,请不要忘记将-m32添加到gcc