我一直在实现一个简单的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
。 这是混淆(无论是为读者,也可能是为编译器;当你不通过-ffreestanding
对gcc
很-ffreestanding
它是处理main
非常具体)。 使用其他的东西,如start
或begin_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
。