跳转至

调用约定

本章描述了针对Linx程序的C/C++编译器标准的调用约定

数据类型与对齐

下表总结了Linx原生支持的数据类型。

C类型 描述 Linx字节数
char 字符/字节值 1
short 短整数 2
int 整数 4
long 长整数 8
long long 长长整数 8
void* 指针 8
float 单精度浮点数 4
double 双精度浮点数 8
long double 扩展精度浮点数 16
  • char和unsigned char为8位无符号整数,存入Linx整数寄存器时进行零扩展。unsigned short为16位无符号整数,存入寄存器时同样零扩展
  • signed char为8位有符号整数,存入寄存器时进行符号扩展(即高位63至7位全部填充符号位)
  • short为16位有符号整数,存入寄存器时进行符号扩展。
  • 32位类型(如int)存入整数寄存器时,会作为32位值的符号扩展存储,即第63至31位均与符号位相同。这一限制对无符号32位类型同样适用。编译器及合规软件在内存中存储上述数据类型时均保持自然对齐。

调用约定

Linx调用约定优先通过寄存器传递参数,最多使用8个整数寄存器(a0–a7)。若将函数参数视为具有指针对齐的C结构体字段,参数寄存器对应结构体的前5个指针字。但结构体中联合体或数组内的浮点字段需通过整数寄存器传递。此外,可变参数函数(显式声明的参数除外)的浮点参数也通过整数寄存器传递。

小于指针字长的参数存放在参数寄存器的低位。在小端内存系统中,栈上传递的此类参数在指针字的低位地址对齐。

双倍指针字长的基本类型参数在栈上传递时自然对齐;在整数寄存器中传递时,需占用对齐的奇偶寄存器对,偶寄存器存放低位。

超过双倍指针字长的参数通过引用传递。未通过寄存器传递的参数部分通过栈传递,栈指针sp指向第一个未通过寄存器传递的参数。

函数返回值通过整数寄存器a0和a1。其他不超过两个指针字的值通过a0和a1返回,更大的返回值通过内存传递:调用方分配内存并通过隐式首参传递指针。

标准Linx调用约定中,栈向下增长且栈指针始终保持16字节对齐。

除参数和返回值寄存器外,3个整数寄存器x0–x3,调用后可能失效,需调用方保存;8个整数寄存器s0–s7为保留寄存器,需被调用方保存。下表详述了寄存器的调用约定角色。

寄存器 ABI名称 描述
r0 zero 零寄存器
r1 sp 栈指针寄存器
r2 a0 函数参数0
r3 a1 函数参数1
r4 a2 函数参数2
r5 a3 函数参数3
r6 a4 函数参数4
r7 a5 函数参数5
r8 a6 函数参数6
r9 a7 函数参数7
r10 ra 返回地址寄存器
r11 fp(s0) 帧寄存器/子函数寄存器0
r12 s1 子函数寄存器1
r13 s2 子函数寄存器2
r14 s3 子函数寄存器3
r15 s4 子函数寄存器4
r16 s5 子函数寄存器5
r17 s6 子函数寄存器6
r18 s7 子函数寄存器7
r19 s8 子函数寄存器8
r20 x0 父函数保存其他寄存器0
r21 x1 父函数保存其他寄存器1
r22 x2 父函数保存其他寄存器2
r23 x3 父函数保存其他寄存器3