RISC-V Global Pointer
When programming bare-metal (and probably with OS) RISC-V, correctly managing the global pointer (gp
) is crucial.
The gp
is primarily used to access small data variables with an offset relative to its address, a technique known as linker relaxation.
The gp
should point to the .data
section of your code to efficiently access variables within a ±2048-byte range.
Use the following in your linker script to set the global pointer:
__global_pointer$ = MIN(_sdata + 0x800, MAX(_data + 0x800, _end - 0x800));
If you prefer not to use the gp
, link your program with the --no-relax
flag.
RISC-V programs assume that the gp
register is correctly set, but this may not be the case at boot time.
Therefore, you must initialize the gp
immediately at program start. Use the following assembly code to do so:
.globl _start
.section .text.init
_start
/* Initialize gp */
.option push
.option norelax
la gp,__global_pointer$
.option pop
/* Initialize other variables */
la sp,__stack_top
The norelax
directive temporarily disables linker relaxation when loading the gp
.
Without this, the linker might incorrectly relax the initialization of gp
with mv gp, gp
.
Sources:
risc-v global-pointer assembly linker-script