call伪

call

伪
RISC-V 汇编 参考

lyszt.net 更详细地介绍了 call 和其他 RISC-V 指令。

描述

call 运行一个函数并处理返回值。它跳转到该函数并将返回地址存储在 ra 中,从而使函数能够返回。它是一条伪指令,通常会展开为下面的指令。

jal ra, label

当一个函数距离太远,单次跳转无法到达时,汇编器会替换为一段更长的序列来覆盖这段距离。用函数名编写 call 表明了意图,并将形式的选择留给汇编器。jal 条目描述了跳转和返回地址的保存。下面这一行调用 square 函数。

call square

调用函数还需要就调用者与被调用者之间如何传递信息达成一致。这种一致就是调用约定。调用者将函数的输入放入名为 a0、a1 等的参数寄存器中,并在函数返回后从 a0 读取结果。双方遵循相同的规则,因此分别编写的代码仍能协同工作。

每次 call 都会覆盖 ra。自身进行调用的函数会在调用之前保存它收到的 ra,然后在自己返回之前恢复该值。否则,内层调用的返回地址会替换外层的返回地址,函数就无法返回。不调用其他任何东西的函数无需保存 ra。

RISC-V 手册指出,标准软件调用约定使用 x1 作为返回地址寄存器。jal 可到达正负 1 MiB 范围内的目标,其中 1 MiB 为 1,048,576 字节。更远的目标需要 auipc 后跟 jalr,它可以到达 32 位 pc 相对地址范围内的任何位置。

该示例以 a0 中的 6 调用 square,之后在 a0 中得到 36。参数通过约定传入,结果通过约定传出。

展开为

jal ra, label

汇编器会将此伪指令替换为上面列出的真实指令或指令。

示例

call square      # jumps to square; ra holds the return address