C语言使用MinGW中的GCC生成平面(flat)二进制文件

博主分享了如何在MinGW环境下编译和链接操作系统,解决GCC不支持elf格式及在Windows与Linux之间切换的问题。通过修改Makefile和使用交叉编译器,实现了在Windows下直接生成镜像文件。文章提供了示例代码和Makefile,展示了使用ld脚本和objcopy工具的不同方法,最终成功在MinGW下完成操作系统的编译链接。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近抽空在看自制操作系统相关的书籍,比如《自己动手写操作系统》、《Orange’S:一个操作系统的实现》、《一个64位操作系统的设计与实现》、《30天自制操作系统》等等,只有《30天自制操作系统》是可以完全在Windows下编译、链接、生成镜像的(使用的自制的非标准工具),其它几个全部都是在虚拟机中安装Linux系统,在Windows下编写源码,Linux下进行源码的编译链接,然后生成镜像。这就导致需要在Windows与Linux之间来回切换。

笔者尝试改写书中Makefile,用于MinGW环境下完全编译链接,生成镜像文件,遇到过太多坑。最主要的问题是MinGW中的GCC不支持elf文件格式,而是只能生成PE格式,LD也只能链接PE格式。但是我们需要链接成平面(Flat)二进制或者ELF格式,有一个–oformat binary选项,但是使用它会遇到的问题是:

cannot perform PE operations on non PE output file

网上很多资料都是建议构建一个交叉编译的GCC套件。

笔者后面写的《在MinGW中构建GCC交叉编译器》一文有介绍使用MinGW构建GCC交叉编译器。

就在快要放弃的时候,遇到一个玩具操作系统示例,它就是完全在MinGW下编译、链接生成镜像的,这让我顿时来了兴趣,下面以一个实例来说明。

新建一个目录,在其中创建一个main.c,内容如下:

void start()
{
loop:
	goto loop;
}

再创建一个Makefile文件,内容如下:

CC := gcc
RM := rm
CFLAGS	:= -Wall -fno-builtin -nostdlib -ffreestanding -nostdinc -m32 -fno-pic

all: main.bin

main.exe: main.o
	$(CC) $(CFLAGS) -o main.exe main.o

main.bin: main.exe
	objcopy -O binary main.exe main.bin

%.o: %.c
	$(CC) $(CFLAGS) -o $@ -c $<

clean:
	$(RM) *.o *.exe *.bin

在MinGW控制台中执行make命令,可以看到完全正常编译链接,没有任何错误:
在这里插入图片描述
使用命令

ndisasm main.bin > a.txt

反汇编来看一下:
在这里插入图片描述
可以看到生成了相应的代码,jmp short 0x3就是一直在死循环。

还有一种使用ld的脚本命令作为参数来编译链接,建立一个link.ld文件,内容如下:

OUTPUT_FORMAT("pei-i386")
ENTRY(_start)
phys = 0x00020000;
SECTIONS
{
  .text phys : AT(phys) {
    code = .;
    *(.text)
    *(.rodata)
    . = ALIGN(4096);
  }
  .data : AT(phys + (data - code))
  {
    data = .;
    *(.data)
    . = ALIGN(4096);
  }
  .bss : AT(phys + (bss - code))
  {
    bss = .;
    *(.bss)
    . = ALIGN(4096);
  }
  end = .;
}

然后修改Makefile中的生成命令:

$(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,比如:

objcopy -O elf32-i386 main.exe main.elf

然后可以通过命令objdump -f main.elf查看刚才生成的文件格式:

$ objdump -f main.elf
main.elf:     file format elf32-i386
architecture: i386, flags 0x00000112:
EXEC_P, HAS_SYMS, D_PAGED
start address 0x00020000

原来MinGW环境下要这么玩,终于可以完全在MinGW下编写自己的操作系统了,希望本文对你有所帮助!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值