实际上上面的8和9.,t和s寄存器的可变volatile和保持preserved是对被调用者来说的,也就是对被调用者申明,告诉被调用者, t这些寄存器是可变的,那么被调用者可以随便使用,此时调用者则必须考虑被被调用者随便使用而修改,需要调用者保存; s这些寄存器是保持的,那么被调用者不能随便使用,如果要用就要负责保存。 所以对于a寄存器也可以这样理解,因为a寄存器用于传递参数,所以是被调用者随便使用的,即不保持的,所以需要调用者负责保存,并赋参数值。 Register | ABI Name | Description | Saver | x0 | zero | 硬件固定为0 | / | x1 | ra | 返回地址 | Caller调用者 | x2 | sp | 栈指针 | Callee被调用者 | x3 | gp | 全局指针 | / | x4 | tp | 线程指针 | / | x5-x7 | t0-t2 | 临时使用 | Caller调用者 | x8 | s0/fp | 保存寄存器/帧指针 | Callee被调用者 | x9 | s1 | 保存寄存器 | Callee被调用者 | x10-x11 | a0-a1 | 函数参数/返回值 | Caller调用者 | x12-x17 | a2-a7 | 函数参数 | Caller调用者 | x18-x27 | s2-s11 | 保存寄存器 | Callee被调用者 | x28-x31 | t3-t6 | 临时使用 | Caller调用者 | f0-f7 | ft0-ft7 | FP临时使用 | Caller调用者 | f8-f9 | fs0-fs1 | FP保存寄存器 | Callee被调用者 | f10-f11 | fa0-fa1 | FP函数参数/返回值 | Caller调用者 | f12-f17 | fa2-fa7 | FP参数 | Caller调用者 | f18-f27 | fs2-fs11 | FP保存寄存器 | Callee被调用者 | f28-f31 | ft8-ft11 | FP临时使用 | Caller调用者 | 三.Soft-Float调用约定在没有浮点硬件,或者不使用F,D,Q扩展的硬件浮点,不使用浮点寄存器,完全由软件实现浮点。 整数参数的传入和返回值和RVG一样。 浮点参数和返回值,通过整数寄存器传递,原则是使用大小相同的整数寄存器传递。 比如RV32的 double foo(int, double, long double) 则第一个参数通过a0传递; 第二个参数通过a2和a3传递; 第三个参数通过a4传引用传递; 结果通过a0和a1传递。 如果是RV64则 则第一个参数通过a0传递; 第二个参数通过a1传递; 第三个参数通过a2-a3传递; 结果通过a0传递。 动态舍入模式和产生的异常标志通过C99的fenv.h提供的接口访问。 四.总结从以下几个部分去理解 理解函数参数的传递与返回值,a0-a1,a2-a7,fa0-fa1,fa2-fa7,0-1用于返回值。 理解ra寄存器,函数的返回地址 理解SP栈指针,理解栈的向下生长,理解进入子函数时减少sp分配空间,分配的空间用于存储s寄存器和局部变量使用,和退出子函数时增加sp恢复sp。也就是调用完子函数返回后sp要保持不变。 理解t0-t6,ft0-ft11;s0-s11.fs0-fs11,这里重点站在被调用者角度去理解可变和保持,进而理解谁负责保存寄存器。 jal ra label或者jal ra rd imm简化为伪指令jal label或者jalr rd(立即数为0)。jal跳转即将PC + 4存储到ra寄存器,即函数返回后的下一条执行的指令。jalr类似只是设置PC为rd + imm。 注意与无条件跳转jal x0 label和jalr x0 rd imm,伪指令j label ,jr rd(立即数为0)的区别,无条件跳转是不返回了的所以不保存返回地址到ra,而是保存到了x0寄存器,而x0寄存器是硬件固定为0的,所以相当于不保存, 两者指令是统一的,这也体现了RISC-V指令设计的简洁统一的美学。 其中jal的l可以理解为link,类似于ARM的LR寄存器的L。 除非使用栈传递参数,否则子函数返回后sp必须保持不变。 所有的s寄存器在子函数返回后必须保持,这也是其保持的含义,也是为什么被调用者需要负责保存。 子函数退出时返回ra处执行 函数进入时的处理:减少sp,s寄存器个数和局部变量大小的空间,存储使用到的s寄存器到栈中。如果还有子函数调用则存储ra到栈中(因为子函数的子函数的返回值要存到ra会覆盖ra)。 函数退出时的处理:恢复栈中保存的s寄存器,更新sp值。如果有需要恢复ra值,恢复sp值到函数进入之前的值,返回到ra处执行。 最好通过编写c代码,使用编译工具生成汇编代码,对照c和汇编代码的方式去理解。 五.参考
- riscv-calling.pdf [Volume I: RISC-V User-Level ISA V2.1draft:Chapter 18Calling Convention]
- Understanding RISC-V Calling Convention.pdf [Nick Riasanovsky]
|