1.用c语言生成机器码的意义
前面操作系统的开发我们使用到了汇编语言,而使用汇编语言开发带来的问题就是代码量过于庞大。例如我们需要计算从1到100的加和,那么用汇编语言我们需要如下代码:
RESULT dd 0
mov ax, 0
SUM:
inc word[RESULT]
add ax, word[RESULT]
cmp word[RESULT], 101
jne SUM
同时我们需要时刻注意寄存器的大小与数据是否匹配,使用的内存空间是否与我们所开辟的空间一致。而使用c语言的话,我们只需要如下代码,无需关注寄存器与内存空间的使用,将一切交由编译器来处理:
int result = 0;
for(int i=1;i<=100;i++)
{
result = result + i
}
2.使用gcc编译器将c语言编译为机器码
在对于普通c语言文件的编译中,我们仅需要简单地使用gcc编译器将其编译为可执行文件即可。如:
gcc script.c -o run
其中发生的具体过程如下:
当文件经过汇编后形成的文件script.o与我们之前的loader.bin二进制文件较为相似,区别在于script.o文件包含了一些在当前系统运行所需的数据结构,这些数据结构不是我们所需要的,所以我们在后期将会删去这些数据结构。我们以一个最简单的script.c文件为例:
int main()
{
return 0;
}
我们可以直接通过以下步骤获得script.o目标二进制文件:
gcc -mcmodel=large -fno-builtin -m64 -c script.c
其中-mcmodel=large为将内存范围设置为大型范围,该选项将对代码section的地址和大小不进行限制。-fno-builtin不识别不以__builtin_为前缀的内置函数。-m64生成可运行在64位系统上的文件。此时我们在命令行中可以通过objdump命令查看此目标二进制文件的内容。可以看到其中<main>中的55 48 89 e5 ...即是我们所需要的二进制机器码。
bash# objdump -d script.o
test.o: file format elf64-x86-64
Disassembly of section .text:
0000000000000000 <main>:
0: 55 push %rbp
1: 48 89 e5 mov %rsp,%rbp
4: b8 00 00 00 00 mov $0x0,%eax
9: 5d pop %rbp
a: c3 retq
我们可以使用xxd命令查看该二进制目标文件的纯二进制显示:
bash# xxd script.o
00000000: 7f45 4c46 0201 0100 0000 0000 0000 0000 .ELF............
00000010: 0100 3e00 0100 0000 0000 0000 0000 0000 ..>.............
00000020: 0000 0000 0000 0000 1002 0000 0000 0000 ................
00000030: 0000 0000 4000 0000 0000 4000 0b00 0a00 ....@.....@.....
00000040: 5548 89e5 b800 0000 005d c300 4743 433a UH.......]..GCC:
00000050: 2028 474e 5529 2034 2e38 2e35 2032 3031 (GNU) 4.8.5 201
00000060: 3530 3632 3320 2852 6564 2048 6174 2034 50623 (Red Hat 4
00000070: 2e38 2e35 2d33 3929 0000 0000 0000 0000 .8.5-39)........
00000080: 1400 0000 0000 0000 017a 5200 0178 1001 .........zR..x..
00000090: 1b0c 0708 9001 0000 1c00 0000 1c00 0000 ................
000000a0: 0000 0000 0b00 0000 0041 0e10 8602 430d .........A....C.
000000b0: 0646 0c07 0800 0000 0000 0000 0000 0000 .F..............
000000c0: 0000 0000 0000 0000 0000 0000 0000 0000 ................
......
我们所需要的机器码的偏移量在40处,然而整个目标文件不只包含了我们所需要的机器码,还包括了非常多的数据结构。所以为了得到我们所需要的存粹的机器码,我们需要使用到objcopy工具:
objcopy -I elf64-x86-64 -R ".eh_frame" -O binary script.o script.bin
此时我们再通过xxd查看script.bin文件:
bash# xxd script.bin
00000000: 5548 89e5 b800 0000 005d c3 UH.......].
这样我们获得的script.bin就是我们所需要的可以运行在我们操作系统上的机器码了。