前文《C语言使用MinGW中的GCC生成平面(flat)二进制文件》中有介绍MinGW中使用GCC生成编写操作系统内核所需要的32位平面(flat)二进制文件。但是如果想要在Loader中使用C语言,即编译16位的汇编与C混合代码,就必须使用ELF格式才能转换成16位平面(flat)二进制文件。MinGW默认的GCC只能生成PE文件,不能生成ELF文件,而pei-386是无法转换成16位平面(flat)二进制文件的。
如果在link.ld中使用OUTPUT_FORMAT("pei-i386"),会报错:
mingw32/bin/ld.exe: unsupported PEI architecture: pei-i386
使用使用OUTPUT_FORMAT("binary"),则会报:
mingw32/bin/ld.exe: cannot perform PE operations on non PE output file 'loader.bin'
所以为了能使用MinGW编译16位汇编与C语言的混合代码,就必须编译一个交叉编译器。
下面笔者就以最新的GCC 12.1为例,介绍如何通过MinGW来构建GCC的交叉编译器。笔者的MinGW为MSYS2中的MinGW64。
一、下载Binutils去https://ftp.gnu.org/gnu/binutils/下载最新的binutils,目前最新的为binutils-2.38.tar.xz
二、下载GCC去https://ftp.gnu.org/gnu/gcc/下载最新的GCC,目前最新的为gcc-12.1.0.tar.gz
三、解压、编译 1.解压在$HOME下新建一个目录,比如src,然后将下载的binutils-2.38.tar.xz以及gcc-12.1.0.tar.gz解压到$HOME/src
2.编译binutils在编译之前后设置如下环境变量:
export PREFIX="/opt/cross" export TARGET=i686-elf export PATH="$PREFIX/bin:$PATH"
然后编译、安装binutils:
cd $HOME/src mkdir build-binutils cd build-binutils ../binutils-2.38/configure --target=$TARGET --prefix="$PREFIX" --with-sysroot --disable-nls --disable-werror make make install3. 编译、安装GCC
cd $HOME/src # $PREFIX/bin目录必须在路径中,不然找不到as汇编器 which -- $TARGET-as || echo $TARGET-as is not in the PATH # 进入GCC目录下载必要的依赖 cd gcc-12.1.0/ ./contrib/download_prerequisites cd .. mkdir build-gcc cd build-gcc ../gcc-12.1.0/configure --target=$TARGET --prefix="$PREFIX" --disable-nls --enable-languages=c,c++ --without-headers make all-gcc make all-target-libgcc make install-gcc make install-target-libgcc
编译完成后就可以在$HOME/opt/cross目录下看到相应的程序了:
使用ld -V查看支持的格式:
可以看到已经支持elf_i386了。Btw:从图中可以看到生成的文件都比较大,像i686-elf-lto-dump.exe达370多M,可以通过使用strip命令删除调试信息来瘦身,在所有生成的exe目录使用:
strip *.exe
以下是瘦身后的大小情况:
4.设置路径为了使用编译好的交叉编译器,需要添加到路径,编辑~/.bashrc文件,添加一行:
PATH=$PATH:/opt/cross/bin
原以为构建交叉编译器比较麻烦,有资料的指引还是没遇到坑。如果编译遇到麻烦,或者不想自己编译也可以使用别人编译好的,参见:https://wiki.osdev.org/GCC_Cross-Compiler#Prebuilt Toolchains
有了交叉编译器,就可以使用MinGW构建16位应用程序了,有兴趣的话请关注后面的博文。
参考资料:
https://wiki.osdev.org/GCC_Cross-Compiler



