Skip to content

Commit

Permalink
Relax GOT indirection into PC-relative addressing
Browse files Browse the repository at this point in the history
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.

[1] https://github.com/ARM-software/abi-aa/blob/844a79fd4c77252a11342709e3b27b2c9f590cf1/aaelf64/aaelf64.rst#relocation-optimization
  • Loading branch information
rui314 committed Sep 20, 2023
1 parent 3e4edc7 commit f923a9a
Showing 1 changed file with 74 additions and 0 deletions.
74 changes: 74 additions & 0 deletions riscv-elf.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1567,6 +1567,80 @@ 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 with
an `auipc` + `ld` instruction pair.

Condition::
- `R_RISCV_GOT_HI20` refers to the location 4 bytes before where
`R_RISCV_PCREL_LO12_I` points.

- Both `R_RISCV_GOT_HI20` and `R_RISCV_PCREL_LO12_I` is annotated
with `R_RISCV_RELAX`.

- The symbol pointed to by `R_RISCV_PCREL_LO12_I` is at the location to
which `R_RISCV_GOT_HI20` refers.

- The rd operands of the instructions referred to by `R_RISCV_GOT_HI20`
and `R_RISCV_PCREL_LO12_I` are the same.

- The symbol's address is a link-time constant.

- If the symbol is absolute, the symbol address is within `0x0` ~ `0x7ff`.
Note that an unresolved weak symbol satisfies this condition because such
symbol is handled as if it were an absolute symbol at address 0.

- If the symbol is relative, 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 an `c.li`, `addi` or
`auipc` + `addi` to materialize the symbol's address directly in a
register, 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 (absolute symbol whose address is within `0x0` ~ `0x1f`
and if the RVC instruction is permitted):

[,asm]
----
c.lui t0, <symbol-value>
----

Relaxation result (absolute symbol whose address is larger than `0x1f`
or if the RVC instruction is not permitted):

[,asm]
----
addi t0, zero, <symbol-value>
----

Relaxation result (relative symbol):
[,asm]
----
auipc t0, <hi>
addi t0, t0, <lo>
----
--

==== Zero-page Relaxation

Target Relocation:: R_RISCV_HI20, R_RISCV_LO12_I, R_RISCV_LO12_S
Expand Down

0 comments on commit f923a9a

Please sign in to comment.