共计 1627 个字符,预计需要花费 5 分钟才能阅读完成。
ARM64 架构概述
ARM64(AArch64)作为现代 ARM 架构的 64 位版本,已成为移动设备和服务器领域的主流选择。其特点包括:

- 31 个通用寄存器(x0-x30),比 ARM32 多了一倍
- 独立的 32 个 128 位浮点寄存器(v0-v31)
- 强制 16 字节栈对齐要求
- 更简洁的指令集设计
这些改进使得 ARM64 在保持低功耗优势的同时,获得了接近 x86 平台的性能表现。苹果 M 系列芯片和 AWS Graviton 处理器的成功,证明了 ARM64 在消费级和服务器领域的竞争力。
ARM32 与 ARM64 调用约定对比
- 寄存器数量
- ARM32:15 个通用寄存器(r0-r14),参数通常通过 r0-r3 传递
-
ARM64:31 个通用寄存器(x0-x30),前 8 个寄存器(x0-x7)用于参数传递
-
参数传递规则
- ARM32:前 4 个参数通过寄存器,其余通过栈传递
-
ARM64:前 8 个参数通过寄存器,支持寄存器内浮点参数(v0-v7)
-
栈对齐要求
- ARM32:通常 4 字节对齐
- ARM64:强制 16 字节对齐
ARM64 调用约定核心要素
通用寄存器用途
| 寄存器 | 用途 | 是否调用者保存 |
|---|---|---|
| x0-x7 | 参数传递 / 返回值 | 否 |
| x8 | 间接结果位置寄存器 | 否 |
| x9-x15 | 临时寄存器 | 是 |
| x16-x17 | 平台保留 | 是 |
| x18 | 平台保留 | 否 |
| x19-x28 | 被调用者保存寄存器 | 否 |
| x29 | 帧指针 (fp) | 否 |
| x30 | 链接寄存器 (lr) | 是 |
浮点寄存器规范
- v0-v7:浮点参数传递和返回值
- v8-v15:被调用者保存
- v16-v31:临时寄存器
栈操作要点
- 函数入口必须保证 sp 是 16 字节对齐的
- 局部变量区域需要按类型大小对齐
- 调用其他函数前要确保 sp 满足 16 字节对齐
代码示例分析
整型 / 浮点混合参数传递
// C 函数原型:double foo(int a, float b, double c, long d)
foo:
// 参数传递:// x0 = a (int)
// s0 = b (float) 实际使用 w0 的低 32 位
// d1 = c (double)
// x2 = d (long)
// 函数体开始
scvtf d0, w0 // 将 int 参数 a 转换为 double 存入 d0
fcvt d2, s0 // 将 float 参数 b 转换为 double 存入 d2
fadd d0, d0, d2 // a + b
fadd d0, d0, d1 // + c
scvtf d3, x2 // 将 long 参数 d 转换为 double
fadd d0, d0, d3 // + d
ret // 返回值在 d0 中
变长参数处理
// 类似 printf 的变参函数处理
printf:
stp x29, x30, [sp, #-16]! // 保存帧指针和返回地址
mov x29, sp
// 前 8 个参数在 x0-x7 寄存器中
add x1, sp, #16 // 获取第 9 个参数的栈地址
// 调用 vfprintf
bl vfprintf
ldp x29, x30, [sp], #16 // 恢复寄存器
ret
避坑指南
常见错误
- 寄存器保存不全
- 被调用者必须保存 x19-x28 寄存器
-
调用者需要保存 x0-x7 等临时寄存器
-
栈对齐错误
// 错误示例 sub sp, sp, #24 // 24 不是 16 的倍数 // 正确做法 sub sp, sp, #32 // 向上取整到 16 的倍数 -
浮点参数误用
- 浮点参数必须使用 v0-v7 传递
- 不要混用通用寄存器和浮点寄存器传递同一参数
调试技巧
使用 GDB 检查寄存器状态:
(gdb) info registers
(gdb) p $x0
(gdb) p $d0
检查栈对齐:
and x8, sp, #0xF // 检查低 4 位是否为 0
cbnz x8, .Lerror // 不为 0 则跳转到错误处理
跨平台接口设计思考
要实现兼容 ARM64/x86-64 的接口,建议:
- 限制参数不超过 6 个(x86-64 SysV ABI 限制)
- 避免混合使用整型和浮点参数
- 对大型结构体使用指针而非值传递
- 显式声明函数可见性(
__attribute__((visibility("default")))) - 使用标准类型定义(如 uint32_t 而非 int)
通过合理设计接口边界,可以构建在多种架构上行为一致的动态库。实际开发中,建议使用自动化 ABI 检查工具(如 abi-compliance-checker)验证跨平台兼容性。
正文完
