AArch64寄存器

ARM64(AArch64)的函数调用规则主要遵循 AAPCS64 (Procedure Call Standard for the ARM 64-bit Architecture)。了解这些规则对于编写汇编代码、调试程序或进行性能优化至关重要。

以下是 ARM64 函数调用中寄存器的存储与使用规则详解:


1. 通用寄存器 (X0 - X30)

ARM64 有 31 个 64 位通用寄存器,其用途分为:调用者保存 (Caller-saved) 和 **被调用者保存 (Callee-saved)**。

寄存器 别名 描述与规则 保存者
X0 - X7 参数寄存器 用于传递前 8 个整数或指针参数。X0 也用于存放返回值。 Caller
X8 XR (Indirect result) 间接结果位置寄存器。用于返回大型结构体(由调用者分配空间)。 Caller
X9 - X15 临时寄存器 任意使用的临时变量。 Caller
X16 - X17 IP0, IP1 过程内调用寄存器。通常由链接器(Linker)在插入桩代码(Veneers)时使用。 Caller
X18 PR (Platform) 平台寄存器。保留给操作系统或特定平台使用(如在 iOS 中被禁用或保留)。 -
X19 - X28 临时寄存器 必须在函数返回前恢复原样。 Callee
X29 FP (Frame Pointer) 帧指针。指向当前栈帧的底部,用于回溯堆栈。 Callee
X30 LR (Link Register) 链接寄存器。存储函数返回时的跳转地址(即 ret 指令跳转的位置)。 Callee
SP Stack Pointer 栈指针。始终保持 16 字节对齐。 -
XZR Zero Register 常数 0。只读,写入无效。 -

2. 浮点/向量寄存器 (V0 - V31)

ARM64 提供 32 个 128 位寄存器,用于浮点数(Float/Double)和 SIMD(NEON)指令。

  • V0 - V7: 用于传递浮点参数和返回浮点值(Caller-saved)。
  • V8 - V15: **被调用者保存 (Callee-saved)。但注意:仅需保存低 64 位 (D8-D15)**。如果函数使用了这些寄存器的 128 位,则高 64 位不需要被恢复。
  • V16 - V31: 临时寄存器(Caller-saved)。

3. 参数传递规则

  1. 整数/指针参数
    • 前 8 个参数通过 X0 - X7 传递。
    • 如果参数超过 8 个,剩余参数通过 栈 (Stack) 传递。
  2. 浮点参数
    • 前 8 个浮点/向量参数通过 V0 - V7 传递。
    • 多余的通过栈传递。
  3. 结构体传递
    • 小型结构体(通常 <= 16字节)可以直接放在 X0-X1 中。
    • 大型结构体由调用者在内存中准备好,将地址通过 X8 传入函数。

4. 返回值规则

  • 整数/指针:存放在 X0 中。如果是 128 位的结果,则使用 X0 和 X1
  • 浮点数:存放在 V0 中。
  • 大型结构体:函数将结果写入 X8 指向的内存区域。

5. 栈 (Stack) 的约束

  • 16 字节对齐:在任何对外调用(函数调用)发生时,SP (Stack Pointer) 必须是 16 字节对齐的。否则会导致硬件异常(Alignment Fault)。
  • 向下增长:栈向低地址方向增长。
  • Red Zone:与 x86-64 不同,ARM64 标准 没有 Red Zone(即 SP 指向的地址以下是不安全的,随时可能被信号处理程序覆盖)。

6. 函数调用时的标准动作(汇编视角)

函数开始(Prologue):

1
2
3
stp x29, x30, [sp, #-32]!  // 将 FP 和 LR 压入栈,并向下移动 SP 32 字节
mov x29, sp // 更新 FP 到当前 SP 的位置
stp x19, x20, [sp, #16] // 如果使用了 callee-saved 寄存器,也需要保存

函数返回(Epilogue):

1
2
3
ldp x19, x20, [sp, #16]    // 恢复被保存的寄存器
ldp x29, x30, [sp], #32 // 恢复 FP 和 LR,并将 SP 回退
ret // 跳转到 LR 指向的地址

总结核心记忆点

  • X0-X7:传参和返回值。
  • X19-X28:如果你用了,你就得负责存和取(Callee-saved)。
  • **X30 (LR)**:存的是回家的路。
  • SP:时刻保持 16 字节对齐。
  • V8-V15:浮点数的“非易失”区,但只保一半(64bit)。