9.1. Linker Relaxation
At link time, when all the memory objects have been resolved, the code sequence used to refer to them may be simplified and optimized by the linker by relaxing some assumptions about the memory layout made at compile time.
Some relocation types, in certain situations, indicate to the linker where this can happen. Additionally, some relocation types indicate to the linker the associated parts of a code sequence that can be thusly simplified, rather than to instruct the linker how to apply a relocation.
The linker should only perform such relaxations when a R_RISCV_RELAX relocation is at the same position as a candidate relocation.
As this transformation may delete bytes (and thus invalidate references that are commonly resolved at compile-time, such as intra-function jumps), code generators must in general ensure that relocations are always emitted when relaxation is enabled.
9.1.1. Linker Relaxation Types
The purpose of this section is to describe all types of linker relaxation, the linker may implement a part of linker relaxation type, and can be skipped the relaxation type is unsupported.
Each candidate relocation might fit more than one relaxation type, the linker should only apply one relaxation type.
In the linker relaxation optimization, we introduce a concept called relocation
group; a relocation group consists of 1) relocations associated with the same
target symbol and can be applied with the same relaxation, or 2) relocations
with the linkage relationship (e.g. R_RISCV_PCREL_LO12_S linked with
a R_RISCV_PCREL_HI20); all relocations in a single group must be present in
the same section, otherwise will split into another relocation group.
Every relocation group must apply the same relaxation type, and the linker should not apply linker relaxation to only part of the relocation group.
Applying relaxation on the part of the relocation group might result in a
wrong execution result; for example, a relocation group consists of
lui t0, 0 # R_RISCV_HI20 (foo), lw t1, 0(t0) # R_RISCV_LO12_I (foo), and we
only apply global pointer relaxation on first instruction, then
remove that instruction, and didn’t apply relaxation on the second instruction,
which made the load instruction reference to an unspecified address.
|
9.1.1.1. Function Call Relaxation
- Target Relocation
-
R_RISCV_CALL, R_RISCV_CALL_PLT.
- Description
-
This relaxation type can relax
AUIPC+JALRintoJAL. - Condition
-
The offset between the location of relocation and target symbol or the PLT stub of the target symbol is within +-1MiB.
- Relaxation
-
-
Instruction sequence associated with
R_RISCV_CALLorR_RISCV_CALL_PLTcan be rewritten to a single JAL instruction with the offset between the location of relocation and target symbol.
-
- Example
-
Relaxation candidate:
auipc ra, 0 # R_RISCV_CALL_PLT (symbol), R_RISCV_RELAX jalr ra, ra, 0Relaxation result:
jal ra, 0 # R_RISCV_JAL (symbol)
| Using address of PLT stubs of the target symbol or address target symbol directly will resolve by linker according to the visibility of the target symbol. |
9.1.1.2. Compressed Function Call Relaxation
- Target Relocation
-
R_RISCV_CALL, R_RISCV_CALL_PLT.
- Description
-
This relaxation type can relax
AUIPC+JALRintoC.JALinstruction sequence. - Condition
-
The offset between the location of relocation and target symbol or the PLT stub of the target symbol is within +-2KiB and rd operand of second instruction in the instruction sequence is
X1/RAand if it is RV32. - Relaxation
-
-
Instruction sequence associated with
R_RISCV_CALLorR_RISCV_CALL_PLTcan be rewritten to a singleC.JALinstruction with the offset between the location of relocation and target symbol.
-
- Example
-
Relaxation candidate:
auipc ra, 0 # R_RISCV_CALL_PLT (symbol), R_RISCV_RELAX jalr ra, ra, 0Relaxation result:
c.jal ra, <offset-between-pc-and-symbol>
9.1.1.3. Compressed Tail Call Relaxation
- Target Relocation
-
R_RISCV_CALL, R_RISCV_CALL_PLT.
- Description
-
This relaxation type can relax
AUIPC+JALRintoC.Jinstruction sequence. - Condition
-
The offset between the location of relocation and target symbol or the PLT stub of the target symbol is within +-2KiB and rd operand of second instruction in the instruction sequence is
X0. - Relaxation
-
-
Instruction sequence associated with
R_RISCV_CALLorR_RISCV_CALL_PLTcan be rewritten to a singleC.Jinstruction with the offset between the location of relocation and target symbol.
-
- Example
-
Relaxation candidate:
auipc ra, 0 # R_RISCV_CALL_PLT (symbol), R_RISCV_RELAX jalr x0, ra, 0Relaxation result:
c.j ra, <offset-between-pc-and-symbol>
9.1.1.4. Global-pointer Relaxation
- Target Relocation
-
R_RISCV_HI20, R_RISCV_LO12_I, R_RISCV_LO12_S, R_RISCV_PCREL_HI20, R_RISCV_PCREL_LO12_I, R_RISCV_PCREL_LO12_S
- Description
-
This relaxation type can relax a sequence of the load address of a symbol or load/store with a symbol reference into global-pointer-relative instruction.
- Condition
-
Offset between global-pointer and symbol is within +-2KiB,
R_RISCV_PCREL_LO12_IandR_RISCV_PCREL_LO12_Sresolved as indirect relocation pointer. It will always point to anotherR_RISCV_PCREL_HI20relocation, the symbol pointed byR_RISCV_PCREL_HI20will be used in the offset calculation. - Relaxation
-
-
Instruction associated with
R_RISCV_HI20orR_RISCV_PCREL_HI20can be removed. -
Instruction associated with
R_RISCV_LO12_I,R_RISCV_LO12_S,R_RISCV_PCREL_LO12_IorR_RISCV_PCREL_LO12_Scan be replaced with a global-pointer-relative access instruction.
-
- Example
-
Relaxation candidate:
lui t0, 0 # R_RISCV_HI20 (symbol), R_RISCV_RELAX lw t1, 0(t0) # R_RISCV_LO12_I (symbol), R_RISCV_RELAXRelaxation result:
lw t1, <gp-offset-for-symbol>(gp)
The global-pointer refers to the address of the __global_pointer$
symbol, which is the content of gp register.
|
This relaxation requires the program to initialize the gp register with
the address of __global_pointer$ symbol before accessing any symbol address,
strongly recommended initialize gp at the beginning of the program entry
function like _start, and code fragments of initialization must disable
linker relaxation to prevent initialization instruction relaxed into a NOP-like
instruction (e.g. mv gp, gp).
|
# Recommended way to initialize the gp register.
.option push
.option norelax
1: auipc gp, %pcrel_hi(__global_pointer$)
addi gp, gp, %pcrel_lo(1b)
.option pop
The global pointer is referred to as the global offset table pointer in
many other targets, however, RISC-V uses PC-relative addressing rather than
access GOT via the global pointer register (gp), so we use gp register to
optimize code size and performance of the symbol accessing.
|
9.1.1.5. Zero-page Relaxation
- Target Relocation
-
R_RISCV_HI20, R_RISCV_LO12_I, R_RISCV_LO12_S
- Description
-
This relaxation type can relax a sequence of the load address of a symbol or load/store with a symbol reference into shorter instruction sequence if possible.
- Condition
-
The symbol address located within
0x0~0x7ffor0xfffffffffffff800~0xfffffffffffffffffor RV64 and0xfffff800~0xfffffffffor RV32. - Relaxation
-
-
Instruction associated with
R_RISCV_HI20can be removed if the symbol address satisfies the x0-relative access. -
Instruction associated with
R_RISCV_LO12_IorR_RISCV_LO12_Scan be relaxed into x0-relative access.
-
- Example
-
Relaxation candidate:
lui t0, 0 # R_RISCV_HI20 (symbol), R_RISCV_RELAX lw t1, 0(t0) # R_RISCV_LO12_I (symbol), R_RISCV_RELAXRelaxation result:
lw t1, <address-of-symbol>(x0)
9.1.1.6. Compressed LUI Relaxation
- Target Relocation
-
R_RISCV_HI20, R_RISCV_LO12_I, R_RISCV_LO12_S
- Description
-
This relaxation type can relax a sequence of the load address of a symbol or load/store with a symbol reference into shorter instruction sequence if possible.
- Condition
-
The symbol address can be presented by a
C.LUIplus anADDIor load / store instruction. - Relaxation
-
-
Instruction associated with
R_RISCV_HI20can be replaced withC.LUI. -
Instruction associated with
R_RISCV_LO12_IorR_RISCV_LO12_Sshould keep unchanged.
-
- Example
-
Relaxation candidate:
lui t0, 0 # R_RISCV_HI20 (symbol), R_RISCV_RELAX lw t1, 0(t0) # R_RISCV_LO12_I (symbol), R_RISCV_RELAXRelaxation result:
c.lui t0, <non-zero> # RVC_LUI (symbol), R_RISCV_RELAX lw t1, 0(t0) # R_RISCV_LO12_I (symbol), R_RISCV_RELAX
9.1.1.7. Thread-pointer Relaxation
- Target Relocation
-
R_RISCV_TPREL_HI20, R_RISCV_TPREL_ADD, R_RISCV_TPREL_LO12_I, R_RISCV_TPREL_LO12_S.
- Description
-
This relaxation type can relax a sequence of the load address of a symbol or load/store with a thread-local symbol reference into a thread-pointer-relative instruction.
- Condition
-
Offset between thread-pointer and thread-local symbol is within +-2KiB.
- Relaxation
-
-
Instruction associated with
R_RISCV_TPREL_HI20orR_RISCV_TPREL_ADDcan be removed. -
Instruction associated with
R_RISCV_TPREL_LO12_IorR_RISCV_TPREL_LO12_Scan be replaced with a thread-pointer-relative access instruction.
-
- Example
-
Relaxation candidate:
lui t0, 0 # R_RISCV_TPREL_HI20 (symbol), R_RISCV_RELAX add t0, t0, tp # R_RISCV_TPREL_ADD (symbol), R_RISCV_RELAX lw t1, 0(t0) # R_RISCV_TPREL_LO12_I (symbol), R_RISCV_RELAXRelaxation result:
lw t1, <tp-offset-for-symbol>(tp)