资讯详情

CentOS 7 搭建 AArch64 交叉编译环境全记录:从 EPEL 到 QEMU 7.2 的层层闯关

📅 2026/10/10 2:54:29 | 华诺云谱 👁 阅读
CentOS 7 搭建 AArch64 交叉编译环境全记录:从 EPEL 到 QEMU 7.2 的层层闯关
CentOS 7 搭建 AArch64 交叉编译环境全记录从 EPEL 到 QEMU 7.2 的层层闯关在 CentOS 7.9 上搭建 AArch64 Linux 用户态交叉编译环境我先后遇到了缺少stdio.h、找不到动态加载器、旧版 QEMU 报Illegal instruction最后通过 Arm GNU 工具链和源码编译的 QEMU 7.2成功运行了Hello from AArch64!。本文记录这条完整路径也区分了已经观察到的现象与尚未证实的故障原因。无需真实 ARM 开发板就能在 x86_64 宿主机上完成这个示例的交叉编译与运行验证。时间提醒CentOS 7 已于 2024 年 6 月 30 日结束维护。本文面向仍需维护旧环境的场景使用的是历史版本不代表新项目的推荐选型。原有 CentOS、EPEL、SCL 镜像可能失效安装前需要确认已配置可信的归档源或内部镜像。一、环境与最终结论项目版本宿主机CentOS Linux release 7.9.2009 (Core)内核3.10.0-1160.el7.x86_64宿主机架构x86_64目标平台AArch64ARM64Linux 用户态最终交叉编译器Arm GNU Toolchain 10.3-2021.07前缀aarch64-none-linux-gnu最终验证工具QEMU 7.2.0源码编译的aarch64-linux-userQEMU 构建环境Python 3.6、Ninja、devtoolset-11本文验证成功的组合是Arm GCC 10.3 静态链接的示例程序 QEMU 7.2.0。静态链接减少了运行示例时对目标动态加载器和共享库的依赖但不是唯一选择。动态链接程序也可以通过 QEMU 的-L参数指定匹配的 ARM64 sysroot。二、准备测试程序建立一个固定工作目录避免后续在下载、构建目录之间切换时找不到hello.cmkdir-p$HOME/aarch64-democd$HOME/aarch64-democathello.cEOF #include stdio.h int main(void) { printf(Hello from AArch64!\n); return 0; } EOF后续编译示例都在这个目录中进行。宿主机 GCC 用于构建 QEMU交叉 GCC 用于构建 ARM64 程序两者职责不同切勿混用。三、第一轮EPEL 工具链缺少目标 C 库1. 安装并查看版本在已配置可用 EPEL 源的环境中执行sudoyuminstall-yepel-releasesudoyuminstall-ygcc-aarch64-linux-gnu aarch64-linux-gnu-gcc--version本次环境中的编译器版本为 GCC 4.8.5。2. 尝试编译cd$HOME/aarch64-demoaarch64-linux-gnu-gcc hello.c-ohello_arm64报错的关键信息如下具体行号可能不同hello.c:1:19: fatal error: stdio.h: No such file or directory #include stdio.h ^ compilation terminated.3. 原因与结论当前安装的交叉编译器没有可用的 AArch64 用户态 C 库头文件和库文件。编译器、目标 C 库及其 sysroot 是不同的组成部分安装了 GCC不等于拥有完整的 Linux 用户态开发环境。尝试通过以下名称安装目标 glibc当前仓库也没有对应软件包sudoyuminstall-yglibc-aarch64-linux-gnu# No package glibc-aarch64-linux-gnu available.可以进一步检查编译器配置及头文件搜索路径aarch64-linux-gnu-gcc -print-sysroot aarch64-linux-gnu-gcc-v-Ehello.c-o/dev/null结论本次 EPEL 安装结果不足以直接编译依赖 glibc 的 ARM64 用户态程序。若自行提供匹配的 sysroot仍有可能使用该编译器不能据此认定它完全不能用于用户态开发。因此这里改用自带目标库的 Arm 官方 Linux 工具链。四、第二轮Arm 官方工具链能编译动态程序运行失败1. 下载 Arm GNU Toolchain 13.3先下载到普通用户可写目录再使用管理员权限解压到/optmkdir-p$HOME/aarch64-downloadscd$HOME/aarch64-downloadswgethttps://developer.arm.com/-/media/Files/downloads/gnu/13.3.rel1/binrel/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xzsudotar-xJfarm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu.tar.xz-C/optexportARM13/opt/arm-gnu-toolchain-13.3.rel1-x86_64-aarch64-none-linux-gnu$ARM13/bin/aarch64-none-linux-gnu-gcc--version下载后应按发布方提供的校验信息核验文件。历史下载链接如失效请到 Arm 官方归档页寻找同名发行包。2. 编译并确认目标架构cd$HOME/aarch64-demo$ARM13/bin/aarch64-none-linux-gnu-gcchello.c-ohello_arm64filehello_arm64$ARM13/bin/aarch64-none-linux-gnu-readelf-lhello_arm64file输出包含ARM aarch64和dynamically linkedreadelf可以查看程序请求的动态加载器路径。filehello_arm64 hello_arm64: ELF64-bit LSB executable, ARM aarch64, version1(SYSV), dynamically linked(uses shared libs),forGNU/Linux3.7.0, not stripped3. 使用已有 QEMU 运行本次机器上已有的 QEMU 为 2.0.0。不同机器的安装来源和版本可能不同应以实际输出为准qemu-aarch64--versionqemu-aarch64 ./hello_arm64运行时报错/lib/ld-linux-aarch64.so.1: No such file or directory这是目标动态加载器缺失的问题。宿主机的 x86_64 glibc 不能替代 ARM64 glibc。动态链接的正确方向是提供与程序匹配的目标 sysroot例如ARM13_SYSROOT$($ARM13/bin/aarch64-none-linux-gnu-gcc -print-sysroot)printf%s\n$ARM13_SYSROOTls$ARM13_SYSROOT/lib/ld-linux-aarch64.so.1qemu-aarch64-L$ARM13_SYSROOT./hello_arm64如果输出的 sysroot 为空或该目录下没有目标加载器需要先定位工具链中的实际目标运行库目录不能继续照搬这个路径。即使加载器问题解决旧 QEMU 仍可能存在其他兼容性问题。五、第三轮静态链接后QEMU 2.0 报 SIGILL1. 使用 GCC 13 静态编译cd$HOME/aarch64-demo$ARM13/bin/aarch64-none-linux-gnu-gcchello.c-ohello_arm64-staticqemu-aarch64 ./hello_arm64本次运行结果qemu: uncaught target signal 4 (Illegal instruction) - core dumped Illegal instruction (core dumped)2. 换用 Arm GCC 10.3仍然失败cd$HOME/aarch64-downloadswgethttps://developer.arm.com/-/media/Files/downloads/gnu-a/10.3-2021.07/binrel/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xzsudotar-xfgcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu.tar.xz-C/optexportARM10/opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu$ARM10/bin/aarch64-none-linux-gnu-gcc--versioncd$HOME/aarch64-demo$ARM10/bin/aarch64-none-linux-gnu-gcchello.c-ohello_arm64-staticqemu-aarch64 ./hello_arm64这次仍然出现Illegal instruction。3. 不要把现象直接当成根因SIGILL表示执行遇到了非法指令但仅凭这条信息无法确定具体原因。可能涉及 QEMU 的指令模拟、CPU 特性、目标运行库或其他兼容性问题需要结合故障地址、反汇编及执行日志分析。尤其不能直接断言“glibc 调用了membarrier()宿主机内核不支持所以 QEMU 将其转成 SIGILL”。不支持的系统调用通常表现为ENOSYS若要建立它与 SIGILL 的因果关系还需要额外证据。需要继续定位时可以收集日志qemu-aarch64-strace./hello_arm64 qemu-aarch64-din_asm-Dqemu-arm64.log ./hello_arm64本次可以确认的是两个工具链生成的静态示例都未能在 QEMU 2.0 上运行后续同一 GCC 10.3 示例在 QEMU 7.2 上运行成功。这支持升级 QEMU 的处理方向但不证明某个具体系统调用或指令就是根因也不确定最低可用 QEMU 版本。六、第四轮源码编译 QEMU 7.2验证成功这里只构建 AArch64 Linux 用户态模拟器不构建整机模拟器。1. 安装基础依赖sudoyuminstall-ygcc gcc-cmakegitwgettarxzbzip2\pkgconfig glib2-devel zlib-devel对这个用户态构建目标通常不需要用于图形显示的pixman-devel。依赖是否满足以 QEMUconfigure检查结果为准。2. 准备 Python 3.6QEMU 7.2 要求 Python 3.6 或更高版本CentOS 7 默认的 Python 2.7 不满足要求sudoyuminstall-ypython36 python3.6--versioncommand-vpython3.6不要替换系统/usr/bin/python以免影响 yum 等系统工具。若归档源没有python36应通过可信来源另行安装并在配置 QEMU 时指定其真实路径。3. 准备 Ninja优先尝试软件包安装sudoyuminstall-yninja-build ninja--version如果仓库没有可用版本可以固定到历史版本 Ninja 1.10.2避免直接克隆最新分支引入新的编译器或 Python 要求cd$HOME/aarch64-downloadsgitclone--branchv1.10.2--depth1https://github.com/ninja-build/ninja.git ninja-1.10.2cdninja-1.10.2 python3.6 ./configure.py--bootstrapsudoinstall-m0755 ninja /usr/local/bin/ninjaexportPATH/usr/local/bin:$PATHhash-rninja--version两种安装方式选择一种即可。如果 bootstrap 提示宿主编译器过旧可以先完成下一步再返回构建 Ninja。4. 使用 devtoolset-11 构建 QEMUQEMU 7.2 要求 GCC 至少为 7.4CentOS 7 默认 GCC 4.8.5 不满足要求。本次使用 devtoolset-11sudoyuminstall-ycentos-release-sclsudoyuminstall-ydevtoolset-11-gcc devtoolset-11-gcc-c\devtoolset-11-binutilssource/opt/rh/devtoolset-11/enable gcc--versiong--version这些命令以可用的 CentOS 7 SCL 归档源为前提。若出现镜像失效、404 或找不到软件包应先修复软件源换成某个普通镜像地址并不保证其仍保留 CentOS 7 内容。使用可信归档源时保留 GPG 校验不建议用gpgcheck0绕过问题。source只影响当前 shell。重新打开终端后需要重新启用 devtoolset-11它不会替换系统 GCC也不会替换 ARM64 交叉编译器。5. 下载并编译 QEMU 7.2.0cd$HOME/aarch64-downloadswgethttps://download.qemu.org/qemu-7.2.0.tar.xztar-xJfqemu-7.2.0.tar.xzmkdir-pqemu-7.2.0/buildcdqemu-7.2.0/buildsource/opt/rh/devtoolset-11/enableexportPATH/usr/local/bin:$PATH../configure\--target-listaarch64-linux-user\--prefix/usr/local\--python$(command-vpython3.6)make-j$(nproc)sudomakeinstall下载后同样应核验发布方提供的签名或校验信息。构建时如发生内存不足可以降低并行度例如使用make -j2。查看新版本/usr/local/bin/qemu-aarch64--version本次输出的版本为qemu-aarch64 version 7.2.0这里使用绝对路径避免误调用原来的 QEMU 2.0。6. 最终验证exportARM10/opt/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnucd$HOME/aarch64-demo$ARM10/bin/aarch64-none-linux-gnu-gcchello.c-ohello_arm64-staticfilehello_arm64 /usr/local/bin/qemu-aarch64 ./hello_arm64file输出包含ARM aarch64和statically linked。filehello_arm64 hello_arm64: ELF64-bit LSB executable, ARM aarch64, version1(GNU/Linux), statically linked,forGNU/Linux3.7.0, not stripped程序输出Hello from AArch64!至此交叉编译器、目标 C 库、生成的 ARM64 可执行文件以及 QEMU 用户态执行链路都通过了这个最小示例的验证。七、踩坑总结步骤方案本次结果可以确认的问题1EPEL GCC 4.8.5编译失败当前安装缺少可用的目标 C 库头文件2Arm GCC 13 QEMU 2.0动态链接运行失败未提供目标动态加载器及匹配的运行库3Arm GCC 13 QEMU 2.0静态链接SIGILL具体触发原因未定位4Arm GCC 10.3 QEMU 2.0静态链接SIGILL该示例在旧模拟器上仍然失败5Arm GCC 10.3 QEMU 7.2静态链接成功该组合通过最小用户态示例验证这次搭建中最重要的经验有三点交叉编译器不是完整的目标运行环境。用户态 C 程序还需要目标平台的头文件、库和匹配的 ABI。静态链接只解决部分依赖问题。它不保证指令集、系统调用及模拟器兼容性也不是部署复杂应用时的通用最优方案。记录错误现象也保留归因边界。升级 QEMU 后跑通不等于已经证明旧版本具体缺少哪条指令。此外QEMU Linux 用户态模拟会借助宿主机内核处理系统调用并不会启动一个 ARM64 Linux 内核。Hello World跑通不能代替真实开发板测试也不能证明所有 ARM64 应用、驱动或硬件相关功能都兼容。GCC 版本本身也不能决定目标内核兼容性还要考虑工具链所带目标 glibc 的构建配置、程序实际使用的接口以及 QEMU 的支持情况。本文不据此推导“必须 GCC 10”或“QEMU 5 以上都可以”的通用结论。八、后续计划编写 CMake 交叉编译工具链文件toolchain-aarch64.cmake。交叉编译 OpenSSL、curl 和 SQLite验证更完整的依赖链。用qemu-aarch64 -L sysroot验证动态链接程序。在真实开发板上验证运行库、系统调用和硬件相关行为。有板子后继续实践 U-Boot、设备树及内核驱动开发。希望这份记录能帮助仍在维护 CentOS 7 环境的同学把“能编译”和“能运行”之间的几个关键环节理清楚。参考资料Arm GNU Toolchain 下载与历史版本QEMU 源码下载QEMU 7.2 构建平台要求此链接为当前文档历史版本要求应以 7.2.0 源码中的文档和 configure 检查为准QEMU Linux 用户态模拟文档CentOS Linux 生命周期说明标签嵌入式、Linux、CentOS7、交叉编译、AArch64、ARM64、QEMU
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑