寄存器指南

RISC-V ra / x1 寄存器:返回地址、函数调用与保存责任

ra 是 RISC-V 调用约定中的返回地址寄存器。JAL 或 JALR 以 x1 为目的寄存器时会将下一条指令地址写入 ra;ret 伪指令通过该地址返回。psABI 标记 ra 调用后不保持。

psABI:x1 的 ABI 名称是 ra,含义是 Return address。
ISA:标准调用约定使用 x1 保存调用返回地址。
新手规则:还要继续调用别的函数时,不要假设旧 ra 会自动保留。
物理编号 x1ABI 名 ra保存责任 调用后不保持
角色
函数返回地址
调用约定
调用后不保持
先记一句
jal / jalr 会把下一条指令地址写入 ra,除非 rd 不是 ra。
psABI 规范依据

返回地址寄存器

psABI 将 x1 命名为 ra,用于保存返回地址。它标记为调用后不保持;需要跨调用保留的值必须由代码显式保存。

调用后保持:否
RISC-V psABI integer register convention
快速理解与检索要点

ra / x1 是 psABI 的返回地址寄存器。使用 x1 作为链接目的寄存器的调用序列会把下一条指令地址写入这里;它不是调用后保持寄存器,需要跨调用保留的值必须显式保存。

psABI 将 x1 命名为 ra,含义是 return address。
ra 调用后不保持;嵌套调用前需要保存仍要使用的返回地址。

适合什么时候用

  • - JAL 或 JALR 以 ra/x1 为目的寄存器时,ra 保存下一条指令地址。
  • - 需要让 ra 值跨调用保留时,先显式保存它。
  • - ret 是通过 ra/x1 返回的汇编伪指令。

什么时候不要这样用

  • - 不要把 ra 当普通临时寄存器长期存值。
  • - 当调用会以 ra/x1 作为链接目的寄存器且旧值仍需要时,先保存 ra。

调用前后会发生什么

1

jal / jalr 会把下一条指令地址写入 ra,除非 rd 不是 ra。

2

ret 展开为 jalr x0, 0(ra),依赖 ra 中的返回地址。

3

如果函数内部还会调用其他函数,保存和恢复 ra 是当前函数自己的责任。

RV64 非叶子函数保护 ra

示例用于理解规则,不替代完整程序
addi sp, sp, -16
sd   ra, 8(sp)
call foo       # ra 会被覆盖;RV32 保存 32-bit 值时用 sw/lw
ld   ra, 8(sp)
addi sp, sp, 16
ret

常见问题

ra / x1 调用后会自动保持吗?

不会。psABI 标记 ra 调用后不保持;需要跨调用保留时必须显式保存。

为什么再次使用 ra 作为链接目的寄存器会覆盖旧值?

因为以 ra/x1 为链接目的寄存器的 JAL 或 JALR 会写入新的下一条指令地址,从而覆盖旧值。