riscv-mabi

介绍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,他们的差别主要在longvoid *的数据长度上。

  • 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