psABI / RV64 stack-frame simulation

RISC-V 两参数函数调用与 RV64 栈帧动画

示例:caller 调用 foo(3, 5)。参数走 a0/a1;栈空间演示 foo 如何保存 ra/s0、恢复并释放一个 16 字节对齐的栈帧。

本页示例使用 RV64 指令和 32 字节栈帧;实际编译器可能按优化级、省略帧指针或叶子函数规则生成更短序列。

Step 1 / 11

caller

focus
1li a0, 3
2li a1, 5
3call foo
4after_call:
5# a0 = 8
PC
caller
a0
3 (arg0)
a1
5 (arg1)
ra
old ra
栈空间
栈还没动,sp 仍指向 caller 栈顶。
当前 sp
0x80001000
sp 本步不移动
本步没有栈数据移动
高地址栈向低地址增长
future frame range: 0x80000fe0-0x80000fff
每格 8 字节
蓝色箭头 = 当前 sp
0x80001000boundary
调用前栈顶边界
entry spsp
caller stack top
0x80000ff80x80000ff8-0x80000fff
返回地址槽
24(sp)
未分配
0x80000ff00x80000ff0-0x80000ff7
帧指针槽
16(sp)
未分配
0x80000fe80x80000fe8-0x80000fef
局部/临时槽
8(sp)
未分配
0x80000fe00x80000fe0-0x80000fe7
栈帧底部槽
0(sp)
未分配

foo

quiet
1foo:
2addi sp, sp, -32
3sd ra, 24(sp)
4sd s0, 16(sp)
5add a0, a0, a1
6ld s0, 16(sp)
7ld ra, 24(sp)
8addi sp, sp, 32
9ret
PC
idle
ra
-
s0/fp
preserved
a0/a1
args
sp
0x80001000
关键说明

函数调用容易混淆的边界

sp

高亮 addi sp 时,本页显示的是执行前状态;到下一条指令时,sp 才已经移动到新值。

ra

call 写 ra;ret 使用 ra 返回。保存 ra 是函数自己决定的现场保护,不是 call 自动压栈。

s0/fp

s0/fp 只是本例展示的 callee-saved 寄存器;真实函数只保存自己会修改且 ABI 要求保持的寄存器。

语义边界

本页演示普通函数调用,不是 ECALL/trap。函数调用不会切换特权级,也不会自动写 EPC/cause 等 trap 状态。