C语言使用MinGW中的GCC生成平面(flat)二进制文件
最近抽空在看自制操作系统相关的书籍,比如《自己动手写操作系统》、《Orange’S:一个操作系统的实现》、《一个64位操作系统的设计与实现》、《30天自制操作系统》等等,只有《30天自制操作系统》是可以完全在Windows下编译、链接、生成镜像的(使用的自制的非标准工具),其它几个全部都是在虚拟机中安装Linux系统,在Windows下编写源码,Linux下进行源码的编译链接,然后生成镜像。这就导致需要在Windows与Linux之间来回切换。
笔者尝试改写书中Makefile,用于MinGW环境下完全编译链接,生成镜像文件,遇到过太多坑。最主要的问题是MinGW中的GCC不支持elf文件格式,而是只能生成PE格式,LD也只能链接PE格式。但是我们需要链接成平面(Flat)二进制或者ELF格式,有一个–oformat binary
选项,但是使用它会遇到的问题是:
1cannot perform PE operations on non PE output file
网上很多资料都是建议构建一个交叉编译的GCC套件。
笔者后面写的《 在MinGW中构建GCC交叉编译器》一文有介绍使用MinGW构建GCC交叉编译器。
就在快要放弃的时候,遇到一个玩具操作系统示例,它就是完全在MinGW下编译、链接生成镜像的,这让我顿时来了兴趣,下面以一个实例来说明。
新建一个目录,在其中创建一个main.c,内容如下:
1void start()
2{
3loop:
4 goto loop;
5}
再创建一个Makefile文件,内容如下:
1CC := gcc
2RM := rm
3CFLAGS := -Wall -fno-builtin -nostdlib -ffreestanding -nostdinc -m32 -fno-pic
4
5all: main.bin
6
7main.exe: main.o
8 $(CC) $(CFLAGS) -o main.exe main.o
9
10main.bin: main.exe
11 objcopy -O binary main.exe main.bin
12
13%.o: %.c
14 $(CC) $(CFLAGS) -o $@ -c $<
15
16clean:
17 $(RM) *.o *.exe *.bin
在MinGW控制台中执行make命令,可以看到完全正常编译链接,没有任何错误:
使用命令
1ndisasm main.bin > a.txt
反汇编来看一下:
可以看到生成了相应的代码,jmp short 0x3就是一直在死循环。
还有一种使用ld的脚本命令作为参数来编译链接,建立一个link.ld文件,内容如下:
1OUTPUT_FORMAT("pei-i386")
2ENTRY(_start)
3phys = 0x00020000;
4SECTIONS
5{
6 .text phys : AT(phys) {
7 code = .;
8 *(.text)
9 *(.rodata)
10 . = ALIGN(4096);
11 }
12 .data : AT(phys + (data - code))
13 {
14 data = .;
15 *(.data)
16 . = ALIGN(4096);
17 }
18 .bss : AT(phys + (bss - code))
19 {
20 bss = .;
21 *(.bss)
22 . = ALIGN(4096);
23 }
24 end = .;
25}
然后修改Makefile中的生成命令:
1$(CC) $(CFLAGS) -o main.exe main.o -T link.ld
注意输出格式是"pei-i386",而不是ld支持的格式。ld支持的格式为:
再看一下生成的汇编代码:
可以看到,两种方式生成的自己编写的代码是完全一样的,只是后面自动填充的代码不一样。
由于ld默认的入口函数为start所以C文件中也是定义的start函数,不能直接使用main函数作为入口,否则会导致链接失败:
这里有一个技巧,就是不直接使用ld命令来链接,而是让gcc来调用,然后使用objcopy来生成我们想要的平面二进制文件或者ELF文件,当然,如果你想要生成32位elf文件,可以将objcopy的参数改为elf32-i386
,比如:
1objcopy -O elf32-i386 main.exe main.elf
然后可以通过命令objdump -f main.elf
查看刚才生成的文件格式:
1$ objdump -f main.elf
2main.elf: file format elf32-i386
3architecture: i386, flags 0x00000112:
4EXEC_P, HAS_SYMS, D_PAGED
5start address 0x00020000
原来MinGW环境下要这么玩,终于可以完全在MinGW下编写自己的操作系统了,希望本文对你有所帮助!
- 原文作者:Witton
- 原文链接:https://wittonbell.github.io/posts/2022/2022-06-30-C语言使用MinGW中的GCC生成平面flat二进制文件/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. 进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。