附录 C. 伪指令速查表
伪指令(pseudo-instructions)是汇编器提供的语法糖,在汇编时被"展开"为一条或多条真实 RISC-V 指令。理解伪指令的展开规则,有助于阅读反汇编输出和精准控制生成的机器码。以下按功能类别列出 RISC-V 标准伪指令全集。
寄存器间移动
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
mv | mv rd, rs | addi rd, rs, 0 | rd = rs |
not | not rd, rs | xori rd, rs, -1 | rd = ~rs(按位取反) |
neg | neg rd, rs | sub rd, x0, rs | rd = -rs(算术取负) |
negw | negw rd, rs | subw rd, x0, rs | rd = sign_extend(-rs[31:0])(RV64) |
sext.w | sext.w rd, rs | addiw rd, rs, 0 | rd = sign_extend(rs[31:0])(RV64) |
seqz | seqz rd, rs | sltiu rd, rs, 1 | rd = (rs == 0) ? 1 : 0 |
snez | snez rd, rs | sltu rd, x0, rs | rd = (rs != 0) ? 1 : 0 |
sltz | sltz rd, rs | slt rd, rs, x0 | rd = (rs < 0) ? 1 : 0 |
sgtz | sgtz rd, rs | slt rd, x0, rs | rd = (rs > 0) ? 1 : 0 |
立即数加载
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
li | li rd, imm | 由汇编器自动选择最优序列 | 加载 64 位有符号立即数 |
li | li rd, imm(-2048 <= imm < 2048) | addi rd, x0, imm | 小立即数 |
li | li rd, imm(仅低 12 位有效) | addi rd, x0, imm | |
li | li rd, imm(仅高 32 位有效) | lui rd, imm_hi + addi rd, rd, imm_lo | 需要 2 条指令 |
li | li rd, imm(任意 64 位值) | 最多 lui + addi + slli + addi + ... | 汇编器计算最优分解 |
地址加载
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
la | la rd, symbol | auipc rd, %pcrel_hi(symbol); addi rd, rd, %pcrel_lo(label) | 加载符号的绝对地址(PC 相对寻址) |
lla | lla rd, symbol | auipc rd, %pcrel_hi(symbol); addi rd, rd, %pcrel_lo(label) | 加载局部符号地址(同 la) |
lga | lga rd, symbol | auipc rd, %got_pcrel_hi(symbol); ld rd, %got_pcrel_lo(label)(rd) | 通过 GOT 加载全局符号地址(位置无关代码) |
lar | lar rd, symbol | auipc rd, %pcrel_hi(symbol); addi rd, rd, %pcrel_lo(label) | 加载只读符号地址 |
函数调用与跳转
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
call | call symbol | auipc ra, %pcrel_hi(symbol); jalr ra, %pcrel_lo(label)(ra) | 函数调用(返回地址存 ra) |
tail | tail symbol | auipc t1, %pcrel_hi(symbol); jalr x0, %pcrel_lo(label)(t1) | 尾调用优化(不保存返回地址) |
ret | ret | jalr x0, ra, 0 | 函数返回(跳转至 ra) |
j | j label | jal x0, label | 无条件跳转 |
jr | jr rs | jalr x0, rs, 0 | 间接跳转(跳转至寄存器地址) |
jal | jal label | jal x1, label | 带链接跳转(保存返回地址至 ra) |
条件分支扩展
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
beqz | beqz rs, label | beq rs, x0, label | rs == 0 则跳转 |
bnez | bnez rs, label | bne rs, x0, label | rs != 0 则跳转 |
blez | blez rs, label | bge x0, rs, label | rs <= 0 则跳转(有符号) |
bgez | bgez rs, label | bge rs, x0, label | rs >= 0 则跳转(有符号) |
bltz | bltz rs, label | blt rs, x0, label | rs < 0 则跳转(有符号) |
bgtz | bgtz rs, label | blt x0, rs, label | rs > 0 则跳转(有符号) |
bgt | bgt rs1, rs2, label | blt rs2, rs1, label | rs1 > rs2 则跳转(有符号) |
ble | ble rs1, rs2, label | bge rs2, rs1, label | rs1 <= rs2 则跳转(有符号) |
bgtu | bgtu rs1, rs2, label | bltu rs2, rs1, label | rs1 > rs2 则跳转(无符号) |
bleu | bleu rs1, rs2, label | bgeu rs2, rs1, label | rs1 <= rs2 则跳转(无符号) |
CSR 操作
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
csrr | csrr rd, csr | csrrs rd, csr, x0 | 读 CSR(rs1=x0,无写入) |
csrw | csrw csr, rs | csrrw x0, csr, rs | 写 CSR(rd=x0,丢弃旧值) |
csrs | csrs csr, rs | csrrs x0, csr, rs | 置位 CSR(rd=x0,丢弃旧值) |
csrc | csrc csr, rs | csrrc x0, csr, rs | 清除 CSR(rd=x0,丢弃旧值) |
csrwi | csrwi csr, uimm | csrrwi x0, csr, uimm | 立即数写 CSR(uimm[4:0]) |
csrsi | csrsi csr, uimm | csrrsi x0, csr, uimm | 立即数置位 CSR |
csrci | csrci csr, uimm | csrrci x0, csr, uimm | 立即数清除 CSR |
空操作
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
nop | nop | addi x0, x0, 0 | 空操作(不改变任何状态) |
浮点伪指令
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
flw | flw fd, symbol | auipc xN, %pcrel_hi(symbol); flw fd, %pcrel_lo(label)(xN) | 从符号地址加载单精度浮点 |
fld | fld fd, symbol | auipc xN, %pcrel_hi(symbol); fld fd, %pcrel_lo(label)(xN) | 从符号地址加载双精度浮点 |
fsw | fsw fs, symbol, rt | auipc rt, %pcrel_hi(symbol); fsw fs, %pcrel_lo(label)(rt) | 存储单精度浮点至符号地址 |
fsd | fsd fs, symbol, rt | auipc rt, %pcrel_hi(symbol); fsd fs, %pcrel_lo(label)(rt) | 存储双精度浮点至符号地址 |
fmv.s | fmv.s fd, fs | fsgnj.s fd, fs, fs | 单精度浮点寄存器间移动 |
fabs.s | fabs.s fd, fs | fsgnjx.s fd, fs, fs | 单精度浮点绝对值 |
fneg.s | fneg.s fd, fs | fsgnjn.s fd, fs, fs | 单精度浮点取负 |
fmv.d | fmv.d fd, fs | fsgnj.d fd, fs, fs | 双精度浮点寄存器间移动 |
fabs.d | fabs.d fd, fs | fsgnjx.d fd, fs, fs | 双精度浮点绝对值 |
fneg.d | fneg.d fd, fs | fsgnjn.d fd, fs, fs | 双精度浮点取负 |
Load/Store 全局符号
| 伪指令 | 语法 | 展开为 | 说明 |
|---|---|---|---|
lb | lb rd, symbol | auipc rd, %pcrel_hi(symbol); lb rd, %pcrel_lo(label)(rd) | 从符号地址加载字节 |
lh | lh rd, symbol | auipc rd, %pcrel_hi(symbol); lh rd, %pcrel_lo(label)(rd) | 从符号地址加载半字 |
lw | lw rd, symbol | auipc rd, %pcrel_hi(symbol); lw rd, %pcrel_lo(label)(rd) | 从符号地址加载字 |
ld | ld rd, symbol | auipc rd, %pcrel_hi(symbol); ld rd, %pcrel_lo(label)(rd) | 从符号地址加载双字 |
lbu | lbu rd, symbol | auipc rd, %pcrel_hi(symbol); lbu rd, %pcrel_lo(label)(rd) | 无符号字节加载 |
lhu | lhu rd, symbol | auipc rd, %pcrel_hi(symbol); lhu rd, %pcrel_lo(label)(rd) | 无符号半字加载 |
lwu | lwu rd, symbol | auipc rd, %pcrel_hi(symbol); lwu rd, %pcrel_lo(label)(rd) | 无符号字加载 |
sb | sb rs, symbol, rt | auipc rt, %pcrel_hi(symbol); sb rs, %pcrel_lo(label)(rt) | 存储字节至符号地址 |
sh | sh rs, symbol, rt | auipc rt, %pcrel_hi(symbol); sh rs, %pcrel_lo(label)(rt) | 存储半字至符号地址 |
sw | sw rs, symbol, rt | auipc rt, %pcrel_hi(symbol); sw rs, %pcrel_lo(label)(rt) | 存储字至符号地址 |
sd | sd rs, symbol, rt | auipc rt, %pcrel_hi(symbol); sd rs, %pcrel_lo(label)(rt) | 存储双字至符号地址 |
数据定义伪指令
| 伪指令 | 语法 | 说明 |
|---|---|---|
.section .text | 切换至代码段 | 后续指令放入 .text |
.section .data | 切换至数据段 | 后续数据放入 .data |
.section .rodata | 切换至只读数据段 | |
.section .bss | 切换至未初始化数据段 | |
.globl symbol | 声明全局符号 | 其他文件可引用 |
.local symbol | 声明本地符号 | 仅本文件可见 |
.align n | 对齐至 2^n 字节边界 | 填充 nop / 零 |
.balign n, fill | 对齐至 n 字节,填充 fill | |
.zero n | 预留 n 字节零 | |
.byte expr | 定义 1 字节 | |
.2byte expr / .half | 定义 2 字节 | |
.4byte expr / .word | 定义 4 字节 | |
.8byte expr / .dword | 定义 8 字节 | |
.float value | 定义 4 字节 IEEE 754 单精度 | |
.double value | 定义 8 字节 IEEE 754 双精度 | |
.ascii "string" | 嵌入 ASCII 字符串(无 \0) | |
.asciz "string" / .string | 嵌入 ASCII 字符串(带 \0) | |
.skip n | 跳过 n 字节 | |
.size symbol, expr | 设置符号大小 | ELF 调试信息 |
.type symbol, @function | 标记符号类型 | ELF 符号表 |
汇编控制伪指令
| 伪指令 | 语法 | 说明 |
|---|---|---|
.equ name, value | 定义常量 | 不可重定义 |
.set name, value | 定义可重定义常量 | |
.macro name args ... .endm | 定义宏 | 参数复用 |
.include "file.s" | 包含其他汇编文件 | |
.text | 切换至 .text 段 | 简写 |
.data | 切换至 .data 段 | 简写 |
.rodata | 切换至 .rodata 段 | 简写 |
.bss | 切换至 .bss 段 | 简写 |
.end | 汇编结束标记 |
调用约定快捷伪指令
| 伪指令 | 语法 | 等价操作 | 说明 |
|---|---|---|---|
push {regs} | 汇编器展开 | addi sp, sp, -N; sd reg, offset(sp) | 入栈(RISC-V 无原生 push,由汇编器生成) |
pop {regs} | 汇编器展开 | ld reg, offset(sp); addi sp, sp, N | 出栈 |
注意:RISC-V 没有原生 push/pop 指令,但 GNU 汇编器和部分工具链提供
push/pop宏作为便利。
伪指令数量统计
| 类别 | 数量 |
|---|---|
| 寄存器间移动 | 9 |
| 立即数/地址加载 | 4 |
| 函数调用/跳转 | 6 |
| 条件分支扩展 | 10 |
| CSR 操作 | 7 |
| 空操作 | 1 |
| 浮点运算 | 10 |
| Load/Store 全局符号 | 14 |
| 数据定义 | 18 |
| 汇编控制 | 9 |
| 合计 | 88 |