riscv-programmer

programmer helper

ABI

Assembler mnemonics for RISC-V integer and floating-point registers.

Register ABI Name Description Caller Calee
x0 zero Hard-wired zero
x1 ra Return address *
x2 sp Stack pointer *
x3 gp Global pointer
x4 tp Thread pointer
x5 t0 Temporary/alternate link register *
x6–x7 t1-t2 Temporaries *
x8 s0/fp Saved register/frame pointer *
x9 s1 Saved register *
x10–x11 a0-a1 Function arguments/return values *
x12–x17 a2-a7 Function arguments *
x18–x27 s2-s11 Saved registers *
x28–x31 t3-t6 Temporaries *
f0–f7 ft0-ft7 FP temporaries *
f8–f9 fs0-fs1 FP saved registers *
f10–f11 fa0-fa1 FP arguments/return values *
f12–f17 fa2-fa7 FP arguments *
f18–f27 fs2-fs11 FP saved registers *
f28–f31 ft8-ft11 FP temporaries *

Preprocessor macros

32 bits

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
$ ./riscv-none-embed-gcc -march=rv32i -mabi=ilp32 -E -dM - < /dev/null | egrep -i 'risc|fp[^-]|version|abi|lp' | sort
#define __GXX_ABI_VERSION 1011
#define __STDC_VERSION__ 201112L
#define __VERSION__ "7.1.1 20170509"
#define __riscv 1
#define __riscv_cmodel_medlow 1
#define __riscv_float_abi_soft 1
#define __riscv_xlen 32

$ ./riscv-none-embed-gcc -march=rv32imac -mabi=ilp32 -E -dM - < /dev/null | egrep -i 'risc|fp[^-]|version|abi|lp' | sort
#define __GXX_ABI_VERSION 1011
#define __STDC_VERSION__ 201112L
#define __VERSION__ "7.1.1 20170509"
#define __riscv 1
#define __riscv_atomic 1
#define __riscv_cmodel_medlow 1
#define __riscv_compressed 1
#define __riscv_div 1
#define __riscv_float_abi_soft 1
#define __riscv_mul 1
#define __riscv_muldiv 1
#define __riscv_xlen 32

$ ./riscv-none-embed-gcc -march=rv32imafdc -mabi=ilp32d -E -dM - < /dev/null | egrep -i 'risc|fp[^-]|version|abi|lp' | sort
#define __FP_FAST_FMA 1
#define __FP_FAST_FMAF 1
#define __GXX_ABI_VERSION 1011
#define __STDC_VERSION__ 201112L
#define __VERSION__ "7.1.1 20170509"
#define __riscv 1
#define __riscv_atomic 1
#define __riscv_cmodel_medlow 1
#define __riscv_compressed 1
#define __riscv_div 1
#define __riscv_fdiv 1
#define __riscv_flen 64
#define __riscv_float_abi_double 1
#define __riscv_fsqrt 1
#define __riscv_mul 1
#define __riscv_muldiv 1
#define __riscv_xlen 32

64 bits

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
$ ./riscv-none-embed-gcc -march=rv64i -mabi=lp64 -E -dM - < /dev/null | egrep -i 'risc|fp[^-]|version|abi|lp' | sort
#define _LP64 1
#define __GXX_ABI_VERSION 1011
#define __LP64__ 1
#define __STDC_VERSION__ 201112L
#define __VERSION__ "7.1.1 20170509"
#define __riscv 1
#define __riscv_cmodel_medlow 1
#define __riscv_float_abi_soft 1
#define __riscv_xlen 64

$ ./riscv-none-embed-gcc -march=rv64imac -mabi=lp64 -E -dM - < /dev/null | egrep -i 'risc|fp[^-]|version|abi|lp' | sort
#define _LP64 1
#define __GXX_ABI_VERSION 1011
#define __LP64__ 1
#define __STDC_VERSION__ 201112L
#define __VERSION__ "7.1.1 20170509"
#define __riscv 1
#define __riscv_atomic 1
#define __riscv_cmodel_medlow 1
#define __riscv_compressed 1
#define __riscv_div 1
#define __riscv_float_abi_soft 1
#define __riscv_mul 1
#define __riscv_muldiv 1
#define __riscv_xlen 64

$ ./riscv-none-embed-gcc -march=rv64imafdc -mabi=lp64d -E -dM - < /dev/null | egrep -i 'risc|fp[^-]|version|abi|lp' | sort
#define _LP64 1
#define __FP_FAST_FMA 1
#define __FP_FAST_FMAF 1
#define __GXX_ABI_VERSION 1011
#define __LP64__ 1
#define __STDC_VERSION__ 201112L
#define __VERSION__ "7.1.1 20170509"
#define __riscv 1
#define __riscv_atomic 1
#define __riscv_cmodel_medlow 1
#define __riscv_compressed 1
#define __riscv_div 1
#define __riscv_fdiv 1
#define __riscv_flen 64
#define __riscv_float_abi_double 1
#define __riscv_fsqrt 1
#define __riscv_mul 1
#define __riscv_muldiv 1
#define __riscv_xlen 64

misc

1
2
#define __riscv_xlen 32
#define __riscv_xlen 64
1
2
#define __riscv_cmodel_medlow 1
#define __riscv_cmodel_medany 1
1
2
3
#define __riscv_float_abi_soft 1
#define __riscv_float_abi_single 1
#define __riscv_float_abi_double 1

The gp (Global Pointer) register

gp寄存器是为了优化4K内memory访问的一种解决办法。

linker使用__global_pointer$来比较memory地址,如果在范围内,就替换掉 absolute/pc-relative寻址为gp-relative寻址,这使得代码更有效率。这个处理过程被称为relaxing,也可以使用-Wl,--no-relax来disable掉这个功能。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ cat main.c 
int i;
int main()
{
return i;
}

$ riscv-none-embed-gcc main.c --save-temps
$ cat main.s
...
lui a5,%hi(i)
lw a5,%lo(i)(a5)
...
$ riscv-none-embed-objdump -d a.out
...
101b4: 8341a783 lw a5,-1996(gp) # 11fdc <i>
...

gp寄存器应该在启动代码中加载为__global_pointer$的地址,并且之后不能被改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
	.section .reset_entry,"ax",@progbits
.align 1
.globl _reset_entry
.type _reset_entry, @function
_reset_entry:

.option push
.option norelax
la gp, __global_pointer$
.option pop

la sp, __stack

j _start

4K区域可以位于寻址内存中任意位置,但是为了使优化更有效率,它最好覆盖最频繁使用的RAM区域。对于标准的newlib应用程序,这是分配.sdata部分的区域,因为它包含了诸如_impure_ptr、malloc_sbrk_base等变量。因此,定义应该被放在.sdata部分之前。例如:

1
2
PROVIDE( __global_pointer$ = . + (4K / 2) );
*(.sdata .sdata.*)

区域大小是4K是一位内RISCV立即数为12bit signed值,那就是+/- 2048或+/- 0x800。因为只是有符号的,所以__global_pointer$必须指向区域中间。

源自:

https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/