RISC-V:__global_pointer$ 不念不忘少年蓝@ 2024-04-18 18:40 54阅读 0赞 # RISC-V:\_\_global\_pointer$ # 原文出处:https://gnu-mcu-eclipse.github.io/arch/riscv/programmer/\#the-gp-global-pointer-register The `gp` (Global Pointer) register is a solution to further optimise memory accesses within a single 4KB region. The linker uses the `__global_pointer$` symbol definition to compare the memory addresses and, if within range, it replaces absolute/pc-relative addressing with gp-relative addressing, which makes the code more efficient. This process is also called relaxing, and can be disabled by `-Wl,--no-relax`. $ 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> ... The `gp` register should be loaded during startup with the address of the `__global_pointer$` symbol and should not be changed later. .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 The 4K region can be anywhere in the addressed memory, but, for the optimisation to be effective, it should preferably cover the most intensely used RAM area. For standard newlib applications, this is the area where the `.sdata` section is allocated, since it includes variables like `_impure_ptr`, `__malloc_sbrk_base`, etc. Thus, the definition should be placed right before the `.sdata` section. For example: PROVIDE( __global_pointer$ = . + (4K / 2) ); *(.sdata .sdata.*) The region size is 4K because RISC-V immediate values are 12-bit signed values, which are +/- 2048 in decimal or +/- 0x800 in hex; since the values are signed, the `__global_pointer$` must point to the middle of the region. 注:要让 `relaxing` 优化起作用,编译时要加入 `-msmall-data-limit=n` 参数,有了这个参数,编译器会把内存空间小于 n 字节的静态变量放入 `.sdata` 或者 `.sdata.*` 节,然后链接器将这部分静态变量集中在 `__global_pointer$` \+/- 2K 的范围内。
还没有评论,来说两句吧...