Chapter18
Calling Convention
调用约定
C Datatypes and Alignment
C数据类型与对齐
下表总结了RISC-V程序原生支持的数据类型。long
和指针的宽度与整数寄存器相同,RV32采用ILP32整数类型,RV64采用LP64,float
为32位IEEE 754-2008
浮点数,double
为64位,long double
为128位。char
和unsigned char
等存入整数寄存器时进行零扩展,signed char
和short
进行符号扩展。在存储时会保持上述数据类型自然对齐。

RVG Calling Convention
RVG调用约定
RISC-V调用约定尽可能通过寄存器传递参数,最多使用八个整数寄存器a0-a7
和八个浮点寄存器fa0-fa7
来实现。
如果第
i<8
个参数是浮点类型,则通过浮点寄存器fai
传递,否则通过整数寄存器ai
传递;示例:
void func(int a, float b, double c)
a
->a0
b
->fa0
c
->fa1
浮点参数是联合体(
union
)或结构体数组的字段时,通过整数寄存器传递;示例:
变参函数(如
printf
)中的浮点参数(显式声明在参数列表中的除外)通过整数寄存器传递。示例:
对小于指针字大小的参数,通过参数寄存器的最低有效位传递(如char
参数占用a0
的最低8位)。相应的,在栈上传递的小于指针字大小的参数会出现在指针字的低地址处,这是因为RISC-V采用小端内存系统。
而当原始参数大小是指针字长的两倍时。如果通过栈传递,它们会自然对齐;当通过整数寄存器传递,这些参数会存放在一个对齐的偶数-奇数寄存器对中,其中偶数寄存器存放最低有效位,例如在RV32中,函数void foo(int, long long)
的第一个参数通过a0
传递,第二个参数通过a2
(低32位)和a3
(高32位)传递,而未使用a1
。
对于大小超过指针字长两倍的参数,通过内存引用传递,调用者分配内存并传递指针,例如:
概念中未通过寄存器传递的参数会通过栈传递,栈指针sp
指向第一个未通过寄存器传递的参数。
函数返回值通过整数寄存器a0
、a1
和浮点寄存器fa0
、fa1
传递。大部分能容纳在两个指针字长内的返回值都会通过a0
、a1
返回;只有当浮点值是基本浮点类型或者是仅包含一个或两个浮点字段的结构体成员时才会使用浮点寄存器返回;更大的返回值则完全通过内存返回,调用者会分配内存并隐式传递其指针。
在标志的RISC-V调用约定中,栈向下增长,且栈指针始终保持16字节对齐。
除了参数和返回值寄存器外,还有一些其他寄存器。7个整数寄存器t0-t6
和12个浮点寄存器fs0-fs11
是临时寄存器。它们在调用过程中易失;还有12个整数寄存器s0-s11
和12个浮点寄存器fs0-fs11
在调用期间保留。

Soft-Float Calling Convention
软浮点调用约定
该约定用于不支持浮点硬件的RV32和RV64实现,它完全避免使用浮点指令和浮点寄存器。
Last updated