3. ARM64 交叉编译工具链:安装与验证
在嵌入式 ARM64 开发中,目标硬件(如树莓派、QEMU 模拟的 virt 平台)通常资源有限,无法直接运行本地编译器。因此,我们需要在性能强大的宿主机(x86_64)上安装交叉编译工具链,生成可在 ARM64 目标上执行的代码。本节将带领你完成 aarch64-linux-gnu-gcc 的安装、环境配置、验证,并编写第一个 ARM64 汇编程序。
核心概念:交叉编译(Cross Compilation)是指在一种架构(如 x86_64)上编译出另一种架构(如 ARM64)可执行代码的过程。工具链前缀
aarch64-linux-gnu- 明确标识了目标架构、操作系统和二进制接口。
3.1 安装 aarch64-linux-gnu-gcc
在 Ubuntu/Debian 系统上,推荐使用包管理器直接安装完整的交叉编译工具链。该工具链包含编译器、汇编器、链接器以及针对 ARM64 的 C 标准库。
# 更新软件包列表
sudo apt update
# 安装 ARM64 交叉编译工具链
sudo apt install gcc-aarch64-linux-gnu binutils-aarch64-linux-gnu
# 验证安装是否成功
which aarch64-linux-gnu-gcc
安装完成后,系统会提供以下核心工具(位于 /usr/bin/ 目录下):
| 工具名称 | 功能描述 | 对应原生工具 |
|---|---|---|
aarch64-linux-gnu-gcc |
ARM64 C 语言编译器 | gcc |
aarch64-linux-gnu-as |
ARM64 汇编器(GAS) | as |
aarch64-linux-gnu-ld |
ARM64 链接器 | ld |
aarch64-linux-gnu-objdump |
ARM64 目标文件反汇编工具 | objdump |
aarch64-linux-gnu-readelf |
ARM64 ELF 文件信息查看工具 | readelf |
注意:如果使用 macOS 或 Windows,建议通过 Docker 或虚拟机运行 Ubuntu 环境。Windows 用户也可以使用 WSL2(Windows Subsystem for Linux)获得原生 Linux 体验。
3.2 配置环境变量
为了使用方便,建议将工具链路径添加到 PATH 环境变量中。虽然 Ubuntu 默认安装路径已在 /usr/bin 中,但为了项目管理的清晰性,我们可以在用户配置文件中设置别名或专用变量。
# 编辑 ~/.bashrc 或 ~/.zshrc 文件
echo 'export CROSS_COMPILE=aarch64-linux-gnu-' >> ~/.bashrc
echo 'export CC=${CROSS_COMPILE}gcc' >> ~/.bashrc
echo 'export AS=${CROSS_COMPILE}as' >> ~/.bashrc
echo 'export LD=${CROSS_COMPILE}ld' >> ~/.bashrc
# 使配置生效
source ~/.bashrc
# 验证环境变量
echo $CC
# 输出应为:aarch64-linux-gnu-gcc
设置 CROSS_COMPILE 前缀变量是嵌入式开发中的常见做法,后续在 Makefile 或编译脚本中可以直接引用,方便切换不同架构的工具链。
3.3 验证工具链
编写一个简单的 C 程序并交叉编译,验证工具链是否正常工作。
// hello.c
#include <stdio.h>
int main() {
printf("Hello, ARM64 World!\n");
return 0;
}
# 使用交叉编译器编译
aarch64-linux-gnu-gcc -o hello.arm64 hello.c
# 查看生成文件的架构信息
file hello.arm64
# 输出应包含:ELF 64-bit LSB executable, ARM aarch64
# 使用 readelf 进一步确认
aarch64-linux-gnu-readelf -h hello.arm64 | grep Machine
# 输出应为:Machine: AArch64
验证要点:
file命令显示ARM aarch64,说明目标架构正确。- 在 x86_64 宿主机上直接运行
./hello.arm64会失败(提示Exec format error),这是正常现象,因为架构不匹配。 - 后续章节中,我们将通过 QEMU 用户态模拟来运行此程序。
3.4 编写第一个 ARM64 汇编程序
为了深入理解 ARM64 指令集,我们直接编写一个汇编程序,实现“退出程序并返回状态码”的功能。这是嵌入式系统中最基础的裸机操作。
// exit.s - ARM64 汇编程序
// 功能:调用 Linux 系统调用 exit(42)
.section .text
.global _start
_start:
// 系统调用号:93 (exit) 放入 x8
mov x8, #93
// 退出状态码:42 放入 x0
mov x0, #42
// 执行系统调用
svc #0
// 数据段(可选)
.section .data
// 此处可定义数据,本程序暂不需要
汇编与链接步骤:
# 汇编:将 .s 文件转换为目标文件 .o
aarch64-linux-gnu-as -o exit.o exit.s
# 链接:生成可执行文件
aarch64-linux-gnu-ld -o exit.arm64 exit.o
# 验证文件类型
file exit.arm64
# 输出:ELF 64-bit LSB executable, ARM aarch64
# 查看反汇编,确认指令正确
aarch64-linux-gnu-objdump -d exit.arm64
反汇编输出应包含以下关键指令:
exit.arm64: file format elf64-littleaarch64
Disassembly of section .text:
0000000000400078 <_start>:
400078: d2800ba8 mov x8, #0x5d // #93
40007c: d2800540 mov x0, #0x2a // #42
400080: d4000001 svc #0x0
汇编要点:
.section .text:定义代码段。.global _start:声明_start为全局符号,作为程序入口点。mov x8, #93:ARM64 Linux 系统调用号通过x8寄存器传递,93对应exit系统调用。mov x0, #42:第一个参数(退出码)放入x0。svc #0:超级用户调用(Supervisor Call),触发系统调用。
3.5 工具链工作流程 SVG 图
下图展示了从汇编源代码到 ARM64 可执行文件的完整工具链工作流程:
3.6 常见问题与排查
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
command not found: aarch64-linux-gnu-gcc |
工具链未安装或 PATH 未配置 | 执行 sudo apt install gcc-aarch64-linux-gnu 重新安装 |
file 命令显示 x86-64 架构 |
误用了本地 gcc 而非交叉编译器 | 确认使用 aarch64-linux-gnu-gcc 全名编译 |
汇编时提示 unknown mnemonic |
指令语法错误或使用了不支持的指令 | 检查 ARM64 指令手册,确保指令格式正确 |
链接时提示 cannot find entry symbol _start |
未定义 _start 或拼写错误 |
在汇编代码中添加 .global _start 和 _start: 标签 |
本节总结:
- 成功安装并验证了
aarch64-linux-gnu-gcc交叉编译工具链。 - 掌握了通过
CROSS_COMPILE环境变量管理工具链的方法。 - 编写了第一个 ARM64 汇编程序,理解系统调用
svc的基本用法。 - 熟悉了从
.s源码到.o目标文件再到可执行文件的完整编译流程。