介绍riscv gcc编译选项mabi。
ABI(Application Binary Interface),定义了一套编译规则,例如数据类型的大小、函数调用的规则。
Register Convention
寄存器约定是所有RISCV架构都需要遵守的,无法通过mabi选择修改。
| Name | ABI Mnemonic | Meaning | Preserved across calls? |
|---|---|---|---|
| x0 | zero | Zero | – (Immutable) |
| x1 | ra | Return address | No |
| x2 | sp | Stack pointer | Yes |
| x3 | gp | Global pointer | – (Unallocatable) |
| x4 | tp | Thread pointer | – (Unallocatable) |
| x5-x7 | t0-t2 | Temporary registers | No |
| x8-x9 | s0-s1 | Callee-saved registers | Yes |
| x10-x17 | a0-a7 | Argument registers | No |
| x18-x27 | s2-s11 | Callee-saved registers | Yes |
| x28-x31 | t3-t6 | Temporary registers | No |
| Name | ABI Mnemonic | Meaning | Preserved across calls? |
|---|---|---|---|
| f0-f7 | ft0-ft7 | Temporary registers | No |
| f8-f9 | fs0-fs1 | Callee-saved registers | Yes* |
| f10-f17 | fa0-fa7 | Argument registers | No |
| f18-f27 | fs2-fs11 | Callee-saved registers | Yes* |
| f28-f31 | ft8-ft11 | Temporary registers | No |
Procedure Calling Convention
Named ABIs
所有的ABI选项如下:
- ILP32: Integer calling-convention only, hardware floating-point calling convention is not used (i.e. ELFCLASS32 and EF_RISCV_FLOAT_ABI_SOFT).
- ILP32F: ILP32 with hardware floating-point calling convention for FLEN=32 (i.e. ELFCLASS32 and EF_RISCV_FLOAT_ABI_SINGLE).
- ILP32D: ILP32 with hardware floating-point calling convention for FLEN=64 (i.e. ELFCLASS32 and EF_RISCV_FLOAT_ABI_DOUBLE).
- ILP32E: ILP32E calling-convention only, hardware floating-point calling convention is not used (i.e. ELFCLASS32, EF_RISCV_FLOAT_ABI_SOFT, and EF_RISCV_RVE).
- LP64: Integer calling-convention only, hardware floating-point calling convention is not used (i.e. ELFCLASS64 and EF_RISCV_FLOAT_ABI_SOFT).
- LP64F: LP64 with hardware floating-point calling convention for FLEN=32 (i.e. ELFCLASS64 and EF_RISCV_FLOAT_ABI_SINGLE).
- LP64D: LP64 with hardware floating-point calling convention for FLEN=64 (i.e. ELFCLASS64 and EF_RISCV_FLOAT_ABI_DOUBLE).
- LP64Q: LP64 with hardware floating-point calling convention for FLEN=128 (i.e. ELFCLASS64 and EF_RISCV_FLOAT_ABI_QUAD).
选项主要分为ILP32和LP64两类,分别对应RV32和RV64,他们的差别主要在long和void *的数据长度上。
LP64, LP64F, LP64D, and LP64Q: use the following type sizes and alignments (based on the LP64 convention):
| Type | Size (Bytes) | Alignment (Bytes) |
| ——————– | ———— | —————– |
| bool/Bool | 1 | 1 |
| char | 1 | 1 |
| short | 2 | 2 |
| int | 4 | 4 |
| long | 8 | 8 |
| long long | 8 | 8 |
| __int128 | 16 | 16 |
| void * | 8 | 8 |
| float | 4 | 4 |
| double | 8 | 8 |
| long double | 16 | 16 |
| float _Complex | 8 | 4 |
| double _Complex | 16 | 8 |
| long double _Complex | 32 | 16 |ILP32, ILP32F, ILP32D, and ILP32E: use the following type sizes and alignments (based on the ILP32 convention):
| Type | Size (Bytes) | Alignment (Bytes) |
| ——————– | ———— | —————– |
| bool/_Bool | 1 | 1 |
| char | 1 | 1 |
| short | 2 | 2 |
| int | 4 | 4 |
| long | 4 | 4 |
| long long | 8 | 8 |
| void * | 4 | 4 |
| float | 4 | 4 |
| double | 8 | 8 |
| long double | 16 | 16 |
| float _Complex | 8 | 4 |
| double _Complex | 16 | 8 |
| long double _Complex | 32 | 16 |
选项还分为empty \ f \ d ,他们的差别体现在浮点参数传递上。
| x | 需要浮点扩展指令? | float参数 | double参数 |
|---|---|---|---|
| ilp32/lp64 | 不需要 | 通过整数寄存器(a0-a1)传递 | 通过整数寄存器(a0-a3)传递 |
| ilp32f/lp64f | 需要F扩展 | 通过浮点寄存器(fa0-fa1)传递 | 通过整数寄存器(a0-a3)传递 |
| ilp32d/lp64d | 需要F扩展和D扩展 | 通过浮点寄存器(fa0-fa1)传递 | 通过浮点寄存器(fa0-fa1)传递 |
参考:
https://www.sifive.com/blog/all-aboard-part-1-compiler-args
https://github.com/riscv/riscv-elf-psabi-doc/blob/master/riscv-elf.md