1. 调用约定
首先函数调用约定是给C编译器用的,用于约定怎么处理函数及其参数的传递,对想用汇编写完整C函数的开发者来说是很有用的。包括RV32G和缺少浮点单元的RV32I上的软浮点约定。
不过最新版本的指令集中已经移除调用约定这一部分,而是被移动到了GitHub文档RISCV-elf-psabi-doc中。
(1)数据类型及对齐
RISC-V C天然支持的数据类型包括 (u)char、(u)short、(u)int、(u)long、(u)long long、void、float、double和long double,长度从1~8字节不等。RV32G,任何数据类型的指针宽度都是32位。还有就是RSIC-V上暂没有原生的低字长处理指令char/uchar short/ushort等低精度类型的数据会被当作32位的数据来处理,即在从内存载入数据到寄存器时char/short通过带符号扩展实现,而 uchar/ushort 则通过0扩展来实现。
编译器和兼容软件在保存上述数据类型时一般会保证自然对齐(即其起始内存地址必须是其类型本身长度的整数倍)。
(2)RV32G调用约定
1.RISC-V的函数调用约定,尽可能优先使用寄存器来传递参数。默认有8个整数寄存器a0-a7和8个浮点寄存器fa0-fa7可以用,其中前两个(a0,a1)、(fa0,fa1)也用来返回值传递。
函数参数是结构体时,则参数每一个字段按指针长度对齐,参数寄存器中保存的就是结构体最前面8个指针字长的参数数据。
浮点类型的参数将通过浮点寄存器fai传递,否则通过整数寄存器ai传递。
union类型的一部分或者struct数组的浮点参数将通过整数寄存器传递。
变长函数(variadic fuction)的所有参数(包括浮点)都通过整数寄存器传递。