MIT 6.S081 Lecture 5 Notes
6.S081第五课,教授GBD调试与RISC-V的调用规范。阅读RISC-V Calling Convention,观看课程视频。之前第二节课讲过GDB使用,这节课只是更贴合 RISC-V 的指令与规范,便于日后Lab的调试。
RISC-V Calling Convention
当可能的时候,RISC-V调用传参会仅用寄存器。最多用 8 个整数寄存器 a0-a7
和 8 个浮点数寄存器 fa0-fa7
。
如果函数的参数被概念化为C结构体的字段,每个字段都具有指针对齐,则参数寄存器是该结构体前8个指针字的投影(副本)。如果参数 i < 8
是浮点类型,则在浮点寄存器fai中传递;否则,它将在整数寄存器ai中传递。但作为 union 字段或 struct 数组字段的浮点参数是在整数寄存器中传递的。此外,可变参数函数的浮点参数(除了那些在形参列表中显式命名的)通过整数寄存器传递。
比指针字小的参数被传递到参数寄存器的最低有效位中。相应地,在栈上传递的 sub-pointer-word 参数出现在指针字的较低地址中,因为RISC-V是小端存储。(即 比指针字小的参数 如果通过栈传递,也是出现在低地址)
当在栈上传递两个指针字大小的 primitive arguments 时,它们自然对齐。当它们在整数寄存器中传递时,它们位于一个对齐的偶数-奇数寄存器对中,偶数寄存器保存最低有效位。例如,在RV32中,函数 void foo(int, long long)
在 a0
中传递第一个参数,在 a2
和 a3
中传递第二个参数。a1
中没有传递任何东西。
大于指针字大小两倍的参数通过引用传递。(参数size太大,通过 caller 在栈上开一块内存,然后传地址)
未在参数寄存器中传递的结构体字段在堆栈上传递。堆栈指针sp指向未传入寄存器的第一个参数。(参数寄存器不够用,通过栈来传)
函数返回值从整数寄存器 a0
和 a1
以及浮点寄存器 fa0
和 fa1
传递。只有当浮点值是 primitive 或仅由一个或两个浮点值组成的结构成员时,才会在浮点寄存器中返回浮点值。其他适合两个指针字的返回值在a0和a1中返回。更大的返回值完全在内存中传递;caller 分配这个内存区域,并将指向该区域的指针作为隐式的第一个参数传递给被调用者。
在标准的RISC-V调用规范中,堆栈向下增长,堆栈指针始终保持16字节对齐。
除了参数寄存器和返回值寄存器外,7个整数寄存器 t0-t6
和12个浮点寄存器 ft0-ft11
都是临时寄存器,它们在调用时是不稳定(volatile)的,如果以后使用,调用者必须保存它们。12个整数寄存器 s0-s11
和12个浮点寄存器 fs0-fs11
在调用时 preserved ,如果使用,则必须由被调用方保存。以下为寄存器其ABI名字、负责维护者与描述的表格。
reg | name | saver | description |
---|---|---|---|
x0 | zero | hardwired zero | |
x1 | ra | caller | return address |
x2 | sp | callee | stack pointer |
x3 | gp | global pointer | |
x4 | tp | thread pointer | |
x5-7 | t0-2 | caller | temporary registers |
x8 | s0/fp | callee | saved register / frame pointer |
x9 | s1 | callee | saved register |
x10-11 | a0-1 | caller | function arguments / return values |
x12-17 | a2-7 | caller | function arguments |
x18-27 | s2-11 | callee | saved registers |
x28-31 | t3-6 | caller | temporary registers |
f0-7 | ft0-7 | caller | FP temporaries |
f8-9 | fs0-1 | callee | FP saved registers |
f10-11 | fa0-1 | caller | FP arguments/return values |
f12-17 | fa2-7 | caller | FP arguments |
f18-27 | fs2-11 | callee | FP saved registers |
f28-31 | ft8-11 | caller | FP temporaries |
pc | program counter |
RISC-V 在不支持浮点数寄存器扩展情况下,浮点数会存放于整数寄存器,规则与等大小 size 的整数相同。这种称为 “Soft-Float Calling Convention” 。
Conclusion
这节课主要讲RISV-V调用的规范,以及一些指令、寄存器与栈分配的知识。包括 call 如何跳转地址,相对jump与绝对jump ,调用 Leaf function 不用保存 ra 寄存器;但调用非 Leaf function 需要 caller 进行保存。都是学过的知识,与 xv6 基本思想大同小异。具体的RISC-V指令集架构可以看
- RISC-V ISA specification: https://riscv.org/specifications/ Contains detailed information
- RISC-V ISA Reference: https://rv8.io/isa Overview of instructions
- RISC-V assembly language reference: https://rv8.io/asm Overview of directives, pseudo-instructions, and more