寄存器指南

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

ra 是 RISC-V 调用约定中的返回地址寄存器。调用相关指令通常把下一条指令地址放进 ra,返回时再用这个地址回到调用者;psABI 标记它不是调用后保持寄存器。

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

返回地址寄存器

psABI 将 x1 命名为 ra,用于保存返回地址。它不是 callee-saved;需要跨调用保留时由调用者或当前函数自行保存。

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

ra / x1 是 psABI 的返回地址寄存器。调用序列通常把返回地址放在这里;它不是调用后保持寄存器,非叶子函数需要显式保存。

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

适合什么时候用

  • - 保存当前函数返回地址,通常由 call / jal / jalr 写入。
  • - 叶子函数如果不再调用其他函数,通常可以不额外保存 ra。
  • - 非叶子函数如果还要调用别人,应先把 ra 保存到栈上。

什么时候不要这样用

  • - 不要把 ra 当普通临时寄存器长期存值。
  • - 不要在还没保存 ra 的情况下再次 call,否则返回地址会被覆盖。

调用前后会发生什么

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。