跳至正文
这篇笔记的目录
回到学习目录
技术开发

RISC-V 寄存器

指令通过寄存器快速读取操作数、保存结果;ABI 再约定寄存器如何在函数之间协作。

#RISC-V#xv6#计算机系统#学习笔记

一句话: 指令通过寄存器快速读取操作数、保存结果;ABI 再约定寄存器如何在函数之间协作。

本章导航#

整数寄存器 · ABI 名称 · 函数例子 · PC 与 CSR

学习目标#

  • 认识 x0–x31、ABI 别名及 caller/callee-saved 约定。
  • 阅读函数参数、返回值和栈帧相关汇编。
  • 区分通用寄存器、PC、CSR 和浮点寄存器。

1. 整数寄存器 x0–x31#

基础整数 ISA 有 32 个整数寄存器,编号为 x0 到 x31。RV32 的 XLEN 为 32,RV64 的 XLEN 为 64。PC 是独立的程序计数器,不属于 x0–x31;CSR 也不是普通通用寄存器。

编号ABI 名约定用途跨函数调用保留?
x0zero恒为 0;写入结果被丢弃不适用
x1ra返回地址
x2sp栈指针
x3gp全局指针(平台/ABI 用)
x4tp线程指针
x5–x7t0–t2临时值
x8–x9s0–s1 / fp被调用者保存值;x8 可作帧指针
x10–x17a0–a7参数/返回值;系统调用也使用其中部分寄存器
x18–x27s2–s11被调用者保存值
x28–x31t3–t6临时值

“caller-saved”表示调用者若还需要该值,应在调用前保存;“callee-saved”表示被调用函数要使用它时,必须恢复原值。别名是汇编/ABI 层面的便利名称,底层仍对应同一组 x 寄存器。

2. ABI 名称与调用约定#

在常见 RISC-V ABI 中:

  • 前 8 个整数参数通常放在 a0–a7;更多参数通过栈传递。
  • 整数返回值通常放在 a0(必要时还会用 a1)。
  • 调用指令把返回地址放入 ra;被调用函数若会继续调用其他函数,通常要先保存自己的 ra。
  • 栈向较低地址增长;符合标准 ABI 的代码需维持规定的栈对齐(常见标准 ABI 要求调用边界 16 字节对齐)。
  • s0–s11 由被调用者负责恢复;t0–t6、a0–a7、ra 由调用者按需保存。

具体平台 ABI 会决定浮点参数、数据模型、结构体传参等细节。不要仅凭 ISA 推断整个程序的二进制接口。

3. 一个小例子#

下面是一个叶函数:它不再调用其他函数,因此不用保存 ra;调用者把两个参数放入 a0、a1,返回值仍放在 a0。

# int add2(int x, int y)
add2:
add a0, a0, a1
ret # ret 是 jalr 的常见伪指令

如果函数需要在继续执行时跨越另一次函数调用保留 s0,它必须先保存原 s0,再在返回前恢复。栈帧大小和保存哪些寄存器取决于实际使用情况,编译器会根据 ABI 生成代码。

4. PC、CSR 和特权状态#

  • PC: 当前/下一条指令地址的架构状态。顺序执行时按指令长度前进,分支和跳转会改变它。
  • CSR(控制与状态寄存器): 保存特权级控制、异常/中断原因、页表配置、计数器等状态。访问受特权规则约束,通常使用 csrrwcsrrs 等 CSR 指令。
  • 常见 supervisor CSR: sstatus(状态)、stvec(trap 入口)、sepc(trap 返回 PC)、scause(trap 原因)、satp(地址转换配置)。这些名称不表示普通 x 寄存器。
  • 浮点寄存器: 在实现相应扩展时另有 f0–f31;它们与 x0–x31 分开。

核心结论: 指令集给出寄存器编号和语义;ABI 约定“谁传参、谁保存、结果放哪”。看函数汇编时,两层规则要一起用。

下一篇: 04 · RISC-V 指令详解05 · 汇编实验