导论
自定义编译 GCC 交叉工具链(如使用 Crosstool-NG、Buildroot 或手动从源码构建)相比直接使用发行版预编译包(如 Ubuntu 源中的 gcc-arm-linux-gnueabihf),核心优势在于对底层运行环境与硬件特性的绝对控制权。精确匹配目标系统的 C 运行时库,硬件架构与指令集的深度优化,定制组件版本与最新特性,裁剪体积与消除非必要依赖,统一的调试与内核接口支持。
GCC 是"编译器的编译器框架"平时开发中执行的 gcc 命令只是一个预先编译好的成品(Driver)。而 GCC 源码本身是一个高度模块化的系统套件。本指南将演示如何构建一个交叉编译器(即一种能在当前机器上运行、但为另一种目标机器生成程序的编译器)。你所需要的,仅仅是一个已预装较新版本 GCC 的Linux环境。

编译环境
使用ubuntu22.08 x86_64 GNU/Linux开发环境, 需要安装组件: sudo apt-get install g++ make gawk
准备编译的gcc 7.3.0(2018 年 1 月 25 日 正式发布) 的老版本适配版本适配内核kernel 5.10.1,需要准备如下的组件代码:
bash
binutils-2.32.tar.bz2
cloog-0.18.0.tar.gz
gcc-7.3.0.tar.xz
glibc-2.33.tar.xz
gmp-6.1.2.tar.xz
isl-0.18.tar.bz2
linux-5.10.1.tar.xz
mpc-1.0.3.tar.gz
mpfr-3.1.4.tar.xz
构建左侧的工具链,随后使用这些工具来编译右侧的程序和运行库。实际上并不会去编译目标系统的 Linux 内核,但为了编译目标系统的标准 C 库,确实需要目标系统的内核头文件(Kernel Headers)。
左侧的编译器在工作时会调用汇编器(Assembler)和链接器(Linker)。而下载的其他所有依赖包(如 MPFR、GMP 和 MPC),都会被链接到编译器本身之中。
右侧的架构图展示了一个在目标操作系统上运行的示例程序 a.out,它是由交叉编译器编译生成,并链接了目标系统的标准 C 库与 C++ 库。标准 C++ 库会调用标准 C 库,而 C 库则直接向 AArch64 Linux 内核发起系统调用(System Calls)。

操作步骤
解压所有的压缩文件包:
bash
for f in *.tar*; do tar xf $f; done
cd gcc-7.3.0
ln -s ../mpfr-3.1.4 mpfr
ln -s ../gmp-6.1.2 gmp
ln -s ../mpc-1.0.3 mpc
ln -s ../isl-0.18 isl
ln -s ../cloog-0.18.0
cd ..
如果有需要编译其它gcc版本,在这个下载:gcc版本下载路径
选择一个系统的一个安装目标路径,确认有足够的写入权限,比如我的:
bash
sudo mkdir -p /opt/usr/gcc_cross
sudo chown yz:yz /opt/usr/gcc_cross
export PATH=/opt/usr/gcc_cross/bin:$PATH
编译Binutils
GNU Binutils(Binary Utilities) 是 GNU 工具链中专门用于处理二进制目标文件、汇编代码、静态/动态库以及可执行程序的工具集。在编译流程中,GCC 负责将高级语言(C/C++)翻译为汇编语言,而后续的汇编、链接、符号管理及二进制分析工作,均由 Binutils 完成。
bash
mkdir build-binutils
cd build-binutils/
../binutils-2.32/configure --prefix=/opt/usr/gcc_cross --target=aarch64-linux --disable-multilib
make -j24
make install
cd ..
编译linux kernel 头文件
bash
cd linux-5.10.1/
make ARCH=arm64 INSTALL_HDR_PATH=/opt/usr/gcc_cross/aarch64-linux headers_install
cd ..
编译c/c++编译器
bash
mkdir -p build-gcc
../gcc-7.3.0/configure --prefix=/opt/usr/gcc_cross \
--target=aarch64-linux \
--enable-languages=c,c++ \
--disable-multilib \
--disable-nls \
--disable-libstdcxx-dual-abi
make -j24 all-gcc
make install-gcc
--disable-libstdcxx-dual-abi:强制禁用 GCC 5.1 引入的"C++11 双重 ABI(Dual ABI)"机制
--disable-nls:GCC 的所有诊断信息、报错和警告将强制统一使用原生英文输出
安装 Glibc 头文件和启动文件
bash
mkdir -p build-glibc
cd build-glibc
../glibc-2.33/configure --prefix=/opt/usr/gcc_cross/aarch64-linux \
--build=$MACHTYPE --host=aarch64-linux --target=aarch64-linux \
--with-headers=/opt/usr/gcc_cross/aarch64-linux/include \
--disable-multilib libc_cv_forced_unwind=yes
make install-bootstrap-headers=yes install-headers
make -j24 csu/subdir_lib
install csu/crt1.o csu/crti.o csu/crtn.o /opt/usr/gcc_cross/aarch64-linux/lib
aarch64-linux-gcc -nostdlib -nostartfiles -shared -x c /dev/null -o /opt/usr/gcc_cross/aarch64-linux/lib/libc.so
touch /opt/usr/gcc_cross/aarch64-linux/include/gnu/stubs.h
cd ..
编译gcc的库
bash
cd buil-gcc
make -j24 all-target-libgcc
make install-target-libgcc
cd ..
编译C库
bash
cd build-glibc
make -j24
make install
编译gcc
bash
cd build-gcc
make -j24
make install
cd ..
编译中遇到的报错问题
最后的编译中,会遇到如下的报错:

- 修改
libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc,第 157 行左右,将 #include <sys/ustat.h> 注释掉,第 250 行左右,将 struct_ustat_sz 的定义注释掉 - 修改
libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h,第192行,注释 extern unsigned struct_ustat_sz; - 修改
sanitizer_common_syscalls.inc文件,去掉如下代码:
c
#if !SANITIZER_ANDROID
PRE_SYSCALL(ustat)(long dev, void *ubuf) {}
POST_SYSCALL(ustat)(long res, long dev, void *ubuf) {
if (res >= 0) {
if (ubuf) POST_WRITE(ubuf, struct_ustat_sz);
}
}
#endif // !SANITIZER_ANDROID
ustat 是一个已被彻底废弃的远古系统调用,ustat() 是早期 Unix/Linux 用来查询文件系统空闲块数和 inode 数量的接口。早在数十年前,Linux 就已经全面推荐使用标准的 statvfs() 和 statfs() 来取代它。Glibc 在 2.28 版本彻底删除了 <sys/ustat.h>,意味着在 Glibc 2.34 环境下编译的应用不可能、也无法调用 ustat()。ASan(以及背后的 compiler-rt)会拦截(Intercept)系统中的数百个标准库函数。ASan 之前包含 ustat,唯一的目的只是在极少数老旧程序调用 ustat(dev, &ubuf) 时,顺便检查一下传入的 &ubuf 结构体内存指针是否越界。
交叉编译测试
查看编译的gcc版本信息:
bash
aarch64-linux-g++ -v
Using built-in specs.
COLLECT_GCC=aarch64-linux-g++
COLLECT_LTO_WRAPPER=/opt/usr/gcc_cross/libexec/gcc/aarch64-linux/7.3.0/lto-wrapper
Target: aarch64-linux
Configured with: ../gcc-7.3.0/configure --prefix=/opt/usr/gcc_cross --target=aarch64-linux --enable-languages=c,c++ --disable-multilib --disable-nls --disable-libstdcxx-dual-abi
Thread model: posix
gcc version 7.3.0 (GCC)
参考
对于上面的操作,可以参考如下脚本,执行快速的自动化配置流程