From d71aaf35adece3f9ca5af1ab65bdf84183408588 Mon Sep 17 00:00:00 2001 From: Rui Ueyama Date: Mon, 18 Sep 2023 14:13:59 +0900 Subject: [PATCH] Relax GOT indirection into PC-relative addressing Some psABIs define the linker optimizations to relax a GOT load into a PC-relative address materialization. AArch64 [1] allows the linker to rewrite ADRP+ADD into ADR. x86-64 does the same thing with the `R_X86_64_GOTPCRELX` and `R_X86_64_REX_GOTPCRELX` relocations. In our case, we have lots of AUIPC+LD instruction pairs to load an address from the GOT in our RISC-V programs because `la` assembly pseudo instruction is expanded to that instruction pair. If the PC-relative address loaded by the instruction pair is a link-time constant, we can rewrite the instructions with AUIPC+ADDI to directly materialize the value into a register, which eliminates one memory load. We can't rewrite existing AUIPC+ADDI instruction pairs unconditionally because technically there may exist code that jumps to the middle of the instruction pair. That should be extremely rare, but we can't deny the possibility. Therefore, `R_RISCV_GOT_HI20` is required to be annotated with `R_RISCV_RELAX` in this proposal. Currently, neither gas nor LLVM assembler emit `R_RISCV_RELAX` for `R_RISCV_GOT_HI20`. I have a WIP patch to emit `R_RISCV_RELAX` only for the `la` pseudo instruction. [1] https://github.com/ARM-software/abi-aa/blob/844a79fd4c77252a11342709e3b27b2c9f590cf1/aaelf64/aaelf64.rst#relocation-optimization --- riscv-elf.adoc | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/riscv-elf.adoc b/riscv-elf.adoc index 16214b94..51db4905 100644 --- a/riscv-elf.adoc +++ b/riscv-elf.adoc @@ -1567,6 +1567,55 @@ optimize code size and performance of the symbol accessing. NOTE: Tag_RISCV_x3_reg_usage is treated as 0 if it is not present. +==== GOT load relaxation + + Target Relocation:: R_RISCV_GOT_HI20, R_RISCV_PCREL_LO12_I + + Description:: This relaxation can relax a GOT indirection into PC-relative + addressing. This relaxation is intended to optimize the `la` assembly + pseudo-instruction, which loads a symbol's address from a GOT entry. + + Condition:: + - Both `R_RISCV_GOT_HI20` and `R_RISCV_PCREL_LO12_I` are annotated with + `R_RISCV_RELAX`. + + - `R_RISCV_GOT_HI20` refers to the location 4 bytes before where + `R_RISCV_PCREL_LO12_I` points. + + - The symbol pointed to by `R_RISCV_PCREL_LO12_I` is at the location to + which `R_RISCV_GOT_HI20` refers. + + - The symbol's PC-relative address is a link-time constant. + + - The offset between the location to which `R_RISCV_GOT_HI20` refers and + the target symbol is within +-2GiB. + + Relaxation:: + - Instruction sequence associated with `R_RISCV_GOT_HI20` and + `R_RISCV_PCREL_LO12_I` can be rewritten to a `auipc` and `addi` to + materialize the symbol's address in the PC-relative manner, eliminating + a load from the GOT. + + - If this relaxation eliminates all references to the symbol's GOT slot, + the linker may opt not to create a GOT slot for that symbol. + + Example:: ++ +-- +[,asm] +---- +label: + auipc t0, 0 # R_RISCV_GOT_HI20 (symbol), R_RISCV_RELAX + ld t0, 0(t0) # R_RISCV_PCREL_LO12_I (label), R_RISCV_RELAX +---- +Relaxation result: +[,asm] +---- + auipc t0, + addi t0, t0, +---- +-- + ==== Zero-page Relaxation Target Relocation:: R_RISCV_HI20, R_RISCV_LO12_I, R_RISCV_LO12_S