天天看点

RISC-V调用惯例

寄存器惯例

RISC-V调用惯例

Preserved across calls?

字面意思是跨调用保留,什么意思呢,也就是标记为​

​YES​

​​的寄存器,需要在子程序执行前后保持不变。如何做到这一点呢,那就是子程序使用这些​

​YES​

​​寄存之前,需要把这些寄存器压栈,用完以后从栈中恢复这些寄存器的值。

标记为​​

​NO​

​​的呢,子程序执行的时候是不关心的,如果​

​NO​

​​寄存器,不希望子程序(callee)执行前后被改变,那就需要程序的调用者(caller)在子程序执行前压栈,子程序执行后出栈恢复寄存器值。

总结:标记为​​

​YES​

​​的需要callee保存(子程序自己保存),标记为​

​NO​

​的需要caller保存(调用者保存)。

注意:

保持寄存器值不变的方式不一定只有入栈和出栈,比入SP是​

​YES​

​​子程序调用后保持SP的值不变,那么可以在子程序的开始把

SP减去一个值,在子程序的最后把SP加上一个值,保持调用前后不变。如下面程序片段所示

(gdb) disass main
Dump of assembler code for function main:
   0x0000000000010158 <+0>:     addi       sp,sp,-32 #在这里开辟栈大小
   0x000000000001015a <+2>:     sd         ra,24(sp)
   0x000000000001015c <+4>:     sd         s0,16(sp)
   0x000000000001015e <+6>:     addi       s0,sp,32
   0x0000000000010160 <+8>:     li         a5,1
   0x0000000000010162 <+10>:    sw         a5,-20(s0)
   0x0000000000010166 <+14>:    li         a5,2
   0x0000000000010168 <+16>:    sw         a5,-24(s0)
   0x000000000001016c <+20>:    lw         a4,-20(s0)
   0x0000000000010170 <+24>:    lw         a5,-24(s0)
   0x0000000000010174 <+28>:    addw       a5,a5,a4
   0x0000000000010176 <+30>:    sw         a5,-28(s0)
   0x000000000001017a <+34>:    lw         a5,-28(s0)
   0x000000000001017e <+38>:    mv         a1,a5
   0x0000000000010180 <+40>:    lui        a5,0x1c
   0x0000000000010182 <+42>:    addi       a0,a5,176 # 0x1c0b0
   0x0000000000010186 <+46>:    jal        ra,0x10332 <printf>
   0x000000000001018a <+50>:    li         a5,0
   0x000000000001018c <+52>:    mv         a0,a5
   0x000000000001018e <+54>:    ld         ra,24(sp)
   0x0000000000010190 <+56>:    ld         s0,16(sp)
   0x0000000000010192 <+58>:    addi       sp,sp,32 #用完以后恢复
   0x0000000000010194 <+60>:    ret
End of assembler dump.      

继续阅读