call

RISC-V call 伪指令详解

汇编器伪指令

远距离函数调用伪指令,使用 AUIPC+JALR 形成 PC 相对调用序列。相比 JAL 的 ±1 MiB 限制,call 常用于跨模块、共享库或动态链接函数调用,并可由链接器松弛为更短序列。

你写下的是
call symbol / call rd, symbol
常见真实展开
auipc ra, offset[31:12] jalr ra, offset[11:0](ra) # or call rd, symbol: auipc rd, offset[31:12] jalr rd, offset[11:0](rd)

这条伪指令到底在帮你省什么

JAL 的 ±1 MiB 范围不足以调用较远函数,call 通过 AUIPC+JALR 形成 PC 相对调用序列,覆盖更大的链接范围,是 RISC-V 位置无关代码(PIC)和动态链接的常见基础。

call 的核心作用是“远距离函数调用”。它是汇编器层面的简写;调试、审计或阅读机器码时,应回到页面列出的真实展开指令和相关重定位语义来判断行为。

官方语义核对重点

官方汇编手册把 call 作为汇编器层面的伪指令/别名处理,硬件执行的是展开后的真实指令序列。
真实语义以 AUIPC 等展开指令的 ISA 定义为准;本页不把 call 当作独立硬件 opcode。
涉及符号目标时,最终机器码可能受 R_RISCV_CALL/R_RISCV_CALL_PLT 和链接器松弛影响。

工具链与链接器边界

call 的符号目标通常通过 R_RISCV_CALL 或 R_RISCV_CALL_PLT 相关重定位表达,最终可能松弛为 JAL。
页面中的 AUIPC+JALR 是官方常见长调用形式;最终机器码应以链接后反汇编为准。

展开过程怎么理解

步骤 1
AUIPC ra, offset[31:12]:把当前 PC 与高位 PC 相对偏移相加,结果暂存在 ra。
步骤 2
JALR ra, offset[11:0](ra):用 ra + 低 12 位偏移形成跳转目标,同时把下一条指令地址写回 ra(返回地址)。
步骤 3
显式 rd 变体:AUIPC rd, offset[31:12] 先用 rd 保存中间地址;JALR rd, offset[11:0](rd) 跳转并把返回地址写入 rd。

在 objdump / 反汇编里可能看到什么

反汇编器将 AUIPC+JALR 对显示为 call symbol 或 call rd,symbol。实际编码由链接器松弛决定——近距离可能被优化为单条 JAL。

官方依据与阅读顺序

本页把伪指令当作汇编器层面的别名或宏来解释:先看它会展开成哪些真实指令,再回到官方 ISA 手册理解真实指令的行为。涉及 ABI、重定位或链接器松弛时,以 psABI 文档为准。

什么时候优先想到它

调用距离超过±1 MiB的函数
动态链接库(.so)中的函数调用(PLT 入口)
位置无关代码中的跨模块调用
大型项目中超出 JAL 范围的子程序

容易混淆 / 常见误区

常见展开占用两条指令(AUIPC+JALR);链接器可能把可达目标松弛为单条 JAL
实际目标由 R_RISCV_CALL / R_RISCV_CALL_PLT 等重定位决定,不能只按源码中的 offset 文本理解
不要手工把 call 当作普通地址加载的 %pcrel_hi/%pcrel_lo 序列改写——重定位类型不同
call rd, symbol 形式会把中间 PC 相对地址写入 rd,rd 原有值会被覆盖并最终保存返回地址

常见问题

call 是真实 RISC-V 指令吗?

call 是汇编器伪指令或别名,不是单独硬件 opcode。页面中的“常见真实展开”列出官方展开,真实行为由展开后的 ISA 指令决定。

使用 call 时最容易误解什么?

常见展开占用两条指令(AUIPC+JALR);链接器可能把可达目标松弛为单条 JAL