RISCV 5 RISC-V调用规则
- 1 Register Convention
- 1.1 Integer Register Convention
- 1.2 Floating-point Register Convention
- 2. Procedure Calling Convention
- 2.1 Integer Calling Convention
- 2.2 Hardware Floating-point Calling Convention
- 2.3 ILP32E Calling Convention
- 2.4 Named ABIs
- 2.5 Default ABIs
- 3. C/C++ type details
- 3.1 C/C++ type sizes and alignments
- 3.1.1 ILP32, ILP32F, ILP32D, and ILP32E
- 3.1.2 LP64, LP64F, LP64D, and LP64Q
- 3.2 C/C++ type representations
- 3.3 va_list, va_start, and va_arg
- 4 Linux-specific ABI
- 4.1 Linux-specific C type sizes and alignments
- 4.2 Linux-specific C type representations
RISCV - 1 RV32/64G指令集清单
RISCV - 2 “Zicsr“, CSR Instructions
RISCV -3 RV32I/RV64I基本整型指令集
RISCV - 4 ISA 扩展名命名约定
1 Register Convention
1.1 Integer Register Convention
In the RISCV standard ABI, procedures should not modify the integer registers tp and gp, because signal handlers may rely upon their values.
在RISCV标准 ABI 中,函数调用过程不应修改整数寄存器 tp 和 gp,因为处理程序可能依赖于它们的值。
The presence of a frame pointer is optional. If a frame pointer exists it must reside in x8 (s0), the register remains callee-saved.
帧指针的存在是可选的。如果存在帧指针,它必须位于 x8(s0)寄存器中,该寄存器将保持调用保存状态。
x10-x11也作为返回值寄存器r0-r1。
1.2 Floating-point Register Convention
*: Floating-point values in callee-saved registers are only preserved across calls if they are no larger than the width of a floating-point register in the targeted ABI. Therefore, these registers can always be considered temporaries if targeting the base integer calling convention.
只有当 Callee-saved 寄存器中的浮点数值不大于目标 ABI 中浮点寄存器的宽度时,它们才会在跨调用时被保留。因此,如果使用基整数调用约定,这些寄存器始终可视为临时寄存器。
2. Procedure Calling Convention
2.1 Integer Calling Convention
The base integer calling convention provides eight argument registers, a0-a7, the first two of which are also used to return values(r0-r1).
基整数调用约定提供了八个参数寄存器(a0-a7),其中前两个也用于返回值(r0-r1)。
Scalars that are at most XLEN bits wide are passed in a single argument register, or on the stack by value if none is available. When passed in registers or on the stack, integer scalars narrower than XLEN bits are widened according to the sign of their type up to 32 bits, then sign-extended to XLEN bits. When passed in registers or on the stack, floating-point types narrower than XLEN bits are widened to XLEN bits, with the upper bits undefined.
宽度最多为 XLEN 位的标量会以单个参数寄存器的形式传递,如果没有寄存器,则以值的形式传递到堆栈。在寄存器或堆栈中传递时,宽度小于 XLEN 位的整数标量会根据其类型的符号加宽到 32 位,然后再根据符号加宽到 XLEN 位。在寄存器或堆栈中传递时,比 XLEN 位更小的浮点类型将扩展到 XLEN 位,高位未定义。
Scalars that are 2×XLEN bits wide are passed in a pair of argument registers, with the low-order XLEN bits in the lower-numbered register and the high-order XLEN bits in the higher-numbered register. If no argument registers are available, the scalar is passed on the stack by value. If exactly one register is available, the low-order XLEN bits are passed in the register and the high-order XLEN bits are passed on the stack.
宽度为 2×XLEN 位的标量会在一对参数寄存器中传递,低阶 XLEN 位在编号较低的寄存器中,高阶 XLEN 位在编号较高的寄存器中。如果没有参数寄存器,标量将按值传递到堆栈。如果正好有一个寄存器可用,则低阶 XLEN 位在寄存器中传递,高阶 XLEN 位在堆栈中传递。
Scalars wider than 2×XLEN are passed by reference and are replaced in the argument list with the address.
宽度大于 2×XLEN 的标量通过引用传递,并在参数列表中用地址替换。
Aggregates whose total size is no more than XLEN bits are passed in a register, with the fields laid out as though they were passed in memory. If no register is available, the aggregate is passed on the stack. Aggregates whose total size is no more than 2×XLEN bits are passed in a pair of registers; if only one register is available, the first half is passed in a register and the second half is passed on the stack. If no registers are available, the aggregate is passed on the stack. Bits unused due to padding, and bits past the end of an aggregate whose size in bits is not divisible by XLEN, are undefined.
总大小不超过 XLEN 位的聚合将在寄存器中传递,字段的布局如同在内存中传递一样。如果没有寄存器,则在堆栈中传递聚合。总大小不超过 2×XLEN 位的聚合将在一对寄存器中传递;如果只有一个寄存器可用,则前半部分在寄存器中传递,后半部分在堆栈中传递。如果没有寄存器,则在堆栈中传递总数。由于填充而未使用的比特,以及超过集合末尾的比特(其比特大小不能被 XLEN 除尽)都是未定义的。
Aggregates or scalars passed on the stack are aligned to the greater of the type alignment and XLEN bits, but never more than the stack alignment.
在堆栈中传递的聚合或标量的对齐方式为类型对齐方式和 XLEN 位中的较大值,但绝对不会超过堆栈对齐方式。
Aggregates larger than 2×XLEN bits are passed by reference and are replaced in the argument list with the address, as are C++ aggregates with nontrivial copy constructors, destructors, or vtables.
大于 2×XLEN 位的聚合以引用方式传递,并在参数列表中用地址替换,具有非简单拷贝构造函数、析构函数或 vtables 的 C++ 聚合也是如此。
Empty structs or union arguments or return values are ignored by C compilers which support them as a nonstandard extension. This is not the case for C++, which requires them to be sized types.
空结构体、union 参数或返回值会被 C 编译器忽略,因为 C 编译器将其作为非标准扩展来支持。而 C++ 则不同,它要求它们是有大小的类型。
Bitfields are packed in little-endian fashion. A bitfield that would span the alignment boundary of its integer type is padded to begin at the next alignment boundary. For example, struct { int x : 10; int y : 12; } is a 32-bit type with x in bits 9-0, y in bits 21-10, and bits 31-22 undefined. By contrast, struct { short x : 10; short y : 12; } is a 32-bit type with x in bits 9-0, y in bits 27-16, and bits 31-28 and 15-10 undefined.
位字段以小端方式打包。一个位字段如果跨越了其整数类型的对齐边界,就会被填充到下一个对齐边界开始。例如,struct { int x : 10; int y : 12; } 是一个 32 位类型,其中 x 位于第 9-0 位,y 位于第 21-10 位,第 31-22 位未定义。相反,struct { short x : 10; short y : 12; } 是一个 32 位类型,其中 x 位于第 9-0 位,y 位于第 27-16 位,第 31-28 位和第 15-10 位未定义。
Arguments passed by reference may be modified by the callee.
以引用方式传递的参数可由被调用者修改。
Floating-point reals are passed the same way as aggregates of the same size, complex floating-point numbers are passed the same way as a struct containing two floating-point reals. (This constraint changes when the integer calling convention is augmented by the hardware floating-point calling convention.)
浮点实数的传递方式与相同大小的聚合数相同,复数浮点数的传递方式与包含两个浮点实数的结构体相同。(当硬件浮点调用规范增加了整数调用约定时,这一限制就会改变)。
In the base integer calling convention, variadic arguments are passed in the same manner as named arguments, with one exception. Variadic arguments with 2×XLEN-bit alignment and size at most 2×XLEN bits are passed in an aligned register pair (i.e., the first register in the pair is even-numbered), or on the stack by value if none is available. After a variadic argument has been passed on the stack, all future arguments will also be passed on the stack (i.e. the last argument register may be left unused due to the aligned register pair rule).
在基整数调用规范中,可变参数的传递方式与命名参数相同,但有一个例外。对齐方式为 2×XLEN 位、大小最多为 2×XLEN 位的可变参数,以对齐寄存器对的形式传递(即寄存器对中的第一个寄存器为偶数),如果没有寄存器对,则以值的形式传递到堆栈。一个可变参数传入堆栈后,以后所有参数也将传入堆栈(即由于寄存器对齐规则,最后一个参数寄存器可能未被使用)。
Values are returned in the same manner as a first named argument of the same type would be passed. If such an argument would have been passed by reference, the caller allocates memory for the return value, and passes the address as an implicit first parameter.
返回值的方式与传递同类型第一个命名参数的方式相同。如果该参数通过引用传递,调用者将为返回值分配内存,并将地址作为隐式的第一参数传递。
The stack grows downwards (towards lower addresses) and the stack pointer shall be aligned to a 128-bit boundary upon procedure entry. The first argument passed on the stack is located at offset zero of the stack pointer on function entry; following arguments are stored at correspondingly higher addresses.
堆栈向下增长(向低地址增长),堆栈指针应在程序进入时对齐到 128 位边界。堆栈中传递的第一个参数位于函数入口处堆栈指针的零偏移量处;后面的参数存储在相应的更高地址处。
In the standard ABI, the stack pointer must remain aligned throughout procedure execution. Non-standard ABI code must realign the stack pointer prior to invoking standard ABI procedures. The operating system must realign the stack pointer prior to invoking a signal handler; hence, POSIX signal handlers need not realign the stack pointer. In systems that service interrupts using the interruptee’s stack, the interrupt service routine must realign the stack pointer if linked with any code that uses a non-standard stack-alignment discipline, but need not realign the stack pointer if all code adheres to the standard ABI.
在标准 ABI 中,堆栈指针必须在整个程序执行过程中保持对齐。非标准 ABI 代码必须在调用标准 ABI 程序之前重新对齐堆栈指针。操作系统必须在调用函数处理程序之前重新对齐堆栈指针;因此,POSIX 函数处理程序无需重新对齐堆栈指针。在提供中断服务的系统中使用中断栈,如果中断服务例程与任何使用非标准堆栈对齐规则的代码相连,则必须重新对齐堆栈指针,但如果所有代码都遵守标准 ABI,则无需重新对齐堆栈指针。
Procedures must not rely upon the persistence of stack-allocated data whose addresses lie below the stack pointer.
程序不得依赖地址位于堆栈指针下方的堆栈分配数据的持久性。
Registers s0-s11 shall be preserved across procedure calls. No floating-point registers, if present, are preserved across calls. (This property changes when the integer calling convention is augmented by the hardware floatingpoint calling convention.)
寄存器 s0-s11 应在程序调用时保留。浮点寄存器(如果存在)在调用过程中不会被保留。(当硬件浮点调用约定增加了整数调用规则时,这一属性将发生变化)。
2.2 Hardware Floating-point Calling Convention
The hardware floating-point calling convention adds eight floating-point argument registers, fa0-fa7, the first two of which are also used to return values. Values are passed in floating-point registers whenever possible, whether or not the integer registers have been exhausted.
硬件浮点调用规范增加了 8 个浮点参数寄存器(fa0-fa7),其中前两个也用于返回值。无论整数寄存器是否已用完,只要有可能,就会使用浮点寄存器传递数值。
The remainder of this section applies only to named arguments. Variadic arguments are passed according to the integer calling convention.
本节的其余部分仅适用于命名参数。可变参数根据整数调用规范传递。
For the purposes of this section, FLEN refers to the width of a floating-point register in the ABI. The ABI’s FLEN must be no wider than the ISA’s FLEN. The ISA might have wider floating-point registers than the ABI.
就本节而言,FLEN 指的是 ABI 中浮点寄存器的宽度。 ABI 的 FLEN 不得比 ISA 的 FLEN 宽。 ISA 可能具有比 ABI 更宽的浮点寄存器。
For the purposes of this section, “struct” refers to a C struct with its hierarchy flattened, including any array fields. That is, struct { struct { float f[1]; } g[2]; } and struct { float f; float g; } are treated the same. Fields containing empty structs or unions are ignored while flattening, even in C++, unless they have nontrivial copy constructors or destructors. Fields containing zero-length bit-fields are ignored while flattening. Attributes such as aligned or packed do not interfere with a struct’s eligibility for being passed in registers according to the rules below, i.e. struct { int i; double d; } and struct attribute packed { int i; double d } are treated the same, as are struct { float f; float g; } and struct { float f; float g attribute aligned (8); }.
A real floating-point argument is passed in a floating-point argument register if it is no more than FLEN bits wide and at least one floating-point argument register is available. Otherwise, it is passed according to the integer calling convention. When a floating-point argument narrower than FLEN bits is passed in a floating-point register, it is 1-extended (NaN-boxed) to FLEN bits.
如果实浮点参数的宽度不超过 FLEN 位,且至少有一个浮点参数寄存器可用,则该参数会在浮点参数寄存器中传递。否则,将按照整数调用规范传递。在浮点参数寄存器中传递宽度小于 FLEN 位的浮点参数时,将对其进行 1 扩展(NaN-boxed)至 FLEN 位。
A struct containing just one floating-point real is passed as though it were a standalone floating-point real.
只包含一个浮点实数的结构体在传递时就像传递一个独立的浮点实数一样。
A struct containing two floating-point reals is passed in two floating-point registers, if neither is more than FLEN bits wide and at least two floating-point argument registers are available. (The registers need not be an aligned pair.) Otherwise, it is passed according to the integer calling convention.
如果两个浮点寄存器都不超过 FLEN 位宽并且至少有两个浮点参数寄存器可用,则包含两个浮点实数的结构将传递到两个浮点寄存器中。 (寄存器不必是对齐的对。)否则,它将根据整数调用规范进行传递。
A complex floating-point number, or a struct containing just one complex floating-point number, is passed as though it were a struct containing two floating-point reals.
传递一个复数浮点数或仅包含一个复数浮点数的结构,就好像它是包含两个浮点实数的结构一样。
A struct containing one floating-point real and one integer (or bitfield), in either order, is passed in a floating-point register and an integer register, without extending the integer to XLEN bits, provided the floating-point real is no more than FLEN bits wide and the integer is no more than XLEN bits wide, and at least one floating-point argument register and at least one integer argument register is available. Otherwise, it is passed according to the integer calling convention.
包含一个浮点实数和一个整数(或位域)的结构(无论顺序如何)都会传递到浮点寄存器和整数寄存器中,而不将整数扩展为 XLEN 位,前提是浮点实数不超过 FLEN位宽且整数不超过 XLEN 位宽,并且至少 1 个浮点参数寄存器和至少 1 个整数参数寄存器可用。否则,将根据整数调用约定进行传递。
Unions are never flattened and are always passed according to the integer calling convention.
Unions永远不会被展平,并且始终根据整数调用约定进行传递。
Values are returned in the same manner as a first named argument of the same type would be passed.
返回值的方式与传递相同类型的第一个命名参数相同。
Floating-point registers fs0-fs11 shall be preserved across procedure calls, provided they hold values no more than FLEN bits wide.
浮点寄存器 fs0-fs11 应在函数调用中保留,前提是它们保存的值不超过 FLEN 位宽。
2.3 ILP32E Calling Convention
The ILP32E calling convention is designed to be usable with the RV32E ISA. This calling convention is the same as the integer calling convention, except for the following differences. The stack pointer need only be aligned to a 32-bit boundary. Registers x16-x31 do not participate in the calling convention, so there are only six argument registers, a0-a5, only two callee-saved registers, s0-s1, and only three temporaries, t0-t2.
ILP32E 调用规范设计用于 RV32E ISA。该调用规范与整数调用规范相同,但有以下区别。堆栈指针只需对齐 32 位边界。寄存器 x16-x31 不参与调用规范,因此只有 6 个参数寄存器(a0-a5)、2 个保存值寄存器(s0-s1)和 3 个暂存寄存器(t0-t2)。
If used with an ISA that has any of the registers x16-x31 and f0-f31, then these registers are considered temporaries.
如果与具有 x16-x31 和 f0-f31 寄存器的 ISA 一起使用,这些寄存器将被视为临时寄存器。
The ILP32E calling convention is not compatible with ISAs that have registers that require load and store alignments of more than 32 bits. In particular, this calling convention must not be used with the D ISA extension.
ILP32E 调用约定与寄存器需要超过 32 位的加载和存储排列的 ISA 不兼容。特别是,该调用规范不得与 D ISA 扩展一起使用。
2.4 Named ABIs
This specification defines the following named ABIs:
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).
The ILP32* ABIs are only compatible with RV32* ISAs, and the LP64* ABIs are only compatible with RV64* ISAs. A future version of this specification may define an ILP32 ABI for the RV64 ISA, but currently this is not a supported operating mode.The F ABIs require the F ISA extension, the D ABIs require the D ISA extension, and the LP64Q ABI requires the Q ISA extension.
ILP32 ABI 仅与 RV32 ISA 兼容,LP64 ABI 仅与 RV64 ISA 兼容。该规范的未来版本可能会为 RV64 ISA 定义 ILP32 ABI,但目前这不是受支持的操作模式。 *F ABI 需要 *F ISA 扩展,*D ABI 需要 D ISA 扩展, LP64Q ABI 需要 Q ISA 扩展。
Note: This means code targeting the Zfinx extension always uses the ILP32, ILP32E or LP64 integer calling-convention only ABIs as there is no dedicated hardware floating-point register file.
注意: 这意味着针对 Zfinx 扩展的代码始终只使用 ILP32、ILP32E 或 LP64 整数调用规范 ABI,因为没有专用的硬件浮点寄存器文件。
2.5 Default ABIs
While various different ABIs are technically possible, for software compatibility reasons it is strongly recommended to use the following default ABIs for specific architectures:
虽然技术上可以使用各种不同的 ABI,但出于软件兼容性的考虑,强烈建议针对特定架构使用以下默认 ABI:
on RV32G :ILP32D
on RV64G :LP64D
Note: Although RV64GQ systems can technically use LP64Q, it is strongly recommended to use LP64D on general-purpose RV64GQ systems for compatibility with standard RV64G software.
注意: 尽管 RV64GQ 系统在技术上可以使用 LP64Q,但强烈建议在通用 RV64GQ 系统上使用 LP64D,以便与标准 RV64G 软件兼容。
3. C/C++ type details
3.1 C/C++ type sizes and alignments
There are two conventions for C/C++ type sizes and alignments.
C/C++ 有两种类型大小和对齐方式的规范。
3.1.1 ILP32, ILP32F, ILP32D, and ILP32E
Use the following type sizes and alignments (based on the ILP32 convention):
使用以下字体大小和排列方式(基于 ILP32 约定):
3.1.2 LP64, LP64F, LP64D, and LP64Q
Use the following type sizes and alignments (based on the LP64 convention):
使用以下字体大小和排列方式(基于 LP64 约定):
The alignment of max_align_t is 16.
max_align_t 的对齐方式为 16。
CHAR_BIT is 8.
CHAR_BIT 为 8。
Structs and unions are aligned to the alignment of their most strictly aligned member. The size of any object is a multiple of its alignment.
结构体和联合体按照其最严格对齐的成员的对齐方式对齐。任何对象的大小都是其对齐方式的倍数。
3.2 C/C++ type representations
char is unsigned.
char 是无符号的。
Booleans (bool/_Bool) stored in memory or when being passed as scalar arguments are either 0 (false) or 1 (true).
存储在内存中或作为标量参数传递时的布尔值(bool/_Bool)要么是 0(假),要么是 1(真)。
A null pointer (for all types) has the value zero.
空指针(适用于所有类型)的值为零。
_Float16 is as defined in the C ISO/IEC TS 18661-3 extension.
_Float16 在 C ISO/IEC TS 18661-3 扩展中定义。
_Complex types have the same layout as a struct containing two fields of the corresponding real type (float, double, or long double), with the first member holding the real part and the second member holding the imaginary part.
_复数类型的布局与包含相应实数类型(float、double 或 long double)的两个字段的结构相同,第一个成员表示实部,第二个成员表示虚部。
3.3 va_list, va_start, and va_arg
The va_list type is void*. A callee with variadic arguments is responsible for copying the contents of registers used to pass variadic arguments to the vararg save area, which must be contiguous with arguments passed on the stack. The va_start macro initializes its va_list argument to point to the start of the vararg save area. The va_arg macro will increment its va_list argument according to the size of the given type, taking into account the rules about 2×XLEN aligned arguments being passed in “aligned” register pairs.
va_list 类型为 void*。带有可变参数的被调用者负责将用于传递可变参数的寄存器内容复制到 vararg 保存区域,该区域必须与堆栈上传递的参数相邻。va_start 宏将其 va_list 参数初始化为指向 vararg 保存区域的起点。va_arg 宏将根据给定类型的大小递增 va_list 参数,同时考虑到 2×XLEN 对齐参数在 "对齐 "寄存器对中传递的规则。
4 Linux-specific ABI
Note: This section of the RISC-V calling convention specification only applies to Linux-based systems.
注意: RISC-V 调用约定规范的这一部分仅适用于基于 Linux 的系统。
In order to ensure compatibility between different implementations of the C library for Linux, we provide some extra definitions which only apply on those systems. These are noted in this section.
为了确保 Linux C 库不同实现之间的兼容性,我们提供了一些仅适用于这些系统的额外定义。本节将对这些定义进行说明。
4.1 Linux-specific C type sizes and alignments
The following definitions apply for all ABIs defined in this document. Here there is no differentiation between ILP32 and LP64 abis.
以下定义适用于本文档中定义的所有 ABI。这里不区分 ILP32 和 LP64 abis。
4.2 Linux-specific C type representations
The following definitions apply for all ABIs defined in this document. Here there is no differentiation between ILP32 and LP64 abis.
以下定义适用于本文档中定义的所有 ABI。这里不区分 ILP32 和 LP64 Abis。
wchar_t is signed.
wchar_t 是有符号的。
wint_t is unsigned.
wint_t 是无符号的。