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


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

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

    cannot perform PE operations on non PE output file
    
    • 1

    网上很多资料都是建议构建一个交叉编译的GCC套件,这就搞麻烦了,里面的坑更多,还不如书中的方式,直接虚拟一个Linux系统来得简单省心。

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

    这里以一个实例来说明。

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

    void start()
    {
    loop:
    	goto loop;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    再创建一个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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

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

    ndisasm main.bin > a.txt
    
    • 1

    反汇编来看一下:
    在这里插入图片描述
    可以看到生成了相应的代码,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 = .;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

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

    $(CC) $(CFLAGS) -o main.exe main.o -T link.ld
    
    • 1

    注意输出格式是"pei-i386",而不是ld支持的格式。ld支持的格式为:
    在这里插入图片描述
    再看一下生成的汇编代码:
    在这里插入图片描述
    可以看到,两种方式生成的自己编写的代码是完全一样的,只是后面自动填充的代码不一样。

    这里有一个技巧,就是不直接使用ld命令来链接,而是让gcc来调用,然后使用objcopy来生成我们想要的平面二进制文件。

    由于ld默认的入口函数为start所以C文件中也是定义的start函数,不能直接使用main函数作为入口,否则会导致链接失败:
    在这里插入图片描述
    原来MinGW环境下要这么玩,希望本文对你有所帮助!

  • 相关阅读:
    BIOMOD2模型、MaxEnt模型物种分布模拟,生物多样性生境模拟,论文写作
    Visual Studio上一些Error的解决方案
    第七天 dfs剪枝&优化
    STM32的寄存器操作
    华为云云耀云服务器L实例评测|零基础基于宝塔部署项目
    《Secure Analytics-Federated Learning and Secure Aggregation》论文阅读
    EnvoyFilter实践: 通过解析子域名注入环境标识
    ESP8266-Arduino编程实例-WS2812驱动
    java海城同泽中学图书仓库管理系统计算机毕业设计MyBatis+系统+LW文档+源码+调试部署
    ToBeWritten之威胁狩猎环境应用
  • 原文地址:https://blog.csdn.net/witton/article/details/125543935