Skip to content

Commit

Permalink
RV64ILP32: Adjust address calculation
Browse files Browse the repository at this point in the history
Adjust address calculation for RV64ILP32 ABIs' code model, dynamic
linking and relocation.

Signed-off-by: Guo Ren <[email protected]>
Signed-off-by: Liao Shihua <[email protected]>
Signed-off-by: Jia-Wei Chen <[email protected]>
  • Loading branch information
guoren83 authored and Liaoshihua committed Dec 4, 2024
1 parent 9803707 commit c6e6e39
Showing 1 changed file with 59 additions and 22 deletions.
81 changes: 59 additions & 22 deletions riscv-elf.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,10 @@ in the current code model.

The medium low code model, or `medlow`, allows the code to address the whole RV32
address space or the lower 2 GiB and highest 2 GiB of the RV64 address space
(`0xFFFFFFFF7FFFF800` ~ `0xFFFFFFFFFFFFFFFF` and `0x0` ~ `0x000000007FFFF7FF`).
(LP64*: `0xFFFFFFFF7FFFF800` ~ `0xFFFFFFFFFFFFFFFF` and `0x0` ~ `0x000000007FFFF7FF`)
(RV64ILP32*: `0xFFFFFFFF80000000` ~ `0xFFFFFFFFFFFFFFFF` and `0x0` ~ `0x000000007FFFFFFF`).
By using the `lui` and load / store instructions, when referring to an object, or
`addi`, when calculating an address literal, for example,
`addi` (LP64* & ILP32* ABIs), `addiw` (RV64ILP32* ABIs), when calculating an address literal, for example,
a 32-bit address literal can be produced.

The following instructions show how to load a value, store a value, or calculate
Expand All @@ -42,10 +43,10 @@ an address in the `medlow` code model.
# Calculate address
lui a0, %hi(symbol)
addi a0, a0, %lo(symbol)
addi[w] a0, a0, %lo(symbol)
----

NOTE: The ranges on RV64 are not `0x0` ~ `0x000000007FFFFFFF` and
NOTE: The ranges on RV64 with LP64* ABIs are not `0x0` ~ `0x000000007FFFFFFF` and
`0xFFFFFFFF80000000` ~ `0xFFFFFFFFFFFFFFFF` due to RISC-V's sign-extension of
immediates; the following code fragments show where the ranges come from:
[,asm]
Expand All @@ -59,12 +60,26 @@ lui a0, 0x80000 # a0 = 0xffffffff80000000
addi a0, a0, -0x800 # a0 = a0 + -2048 = 0xFFFFFFFF7FFFF800
----

NOTE: The ranges on RV64 with RV64ILP32* ABIs are `0x0` ~ `0x000000007FFFFFFF` and
`0xFFFFFFFF80000000` ~ `0xFFFFFFFFFFFFFFFF` by changing addi to addiw; the following
code fragments show where the ranges come from:
[,asm]
----
# Largest postive number:
lui a0, 0x7ffff # a0 = 0x7ffff000
addi a0, 0x7ff # a0 = a0 + 2047 = 0x000000007FFFF7FF
# Smallest negative number:
lui a0, 0x80000 # a0 = 0xffffffff80000000
addiw a0, a0, -0x800 # a0 = a0 + -2048 = 0x000000007FFFF800
----

=== Medium any code model

The medium any code model, or `medany`, allows the code to address the range
between -2 GiB and +2 GiB from its position. By using `auipc`
and load / store instructions, when referring to an object, or
`addi`, when calculating an address literal, for example,
`addi` (LP64* & ILP32* ABIs), `addiw` (RV64ILP32* ABIs), when calculating an address literal, for example,
a signed 32-bit offset, relative to the value of the `pc` register,
can be produced.

Expand Down Expand Up @@ -94,7 +109,7 @@ an address in the medany code model.
# Calculate address
.Ltmp2: auipc a0, %pcrel_hi(symbol)
addi a0, a0, %pcrel_lo(.Ltmp2)
addi[w] a0, a0, %pcrel_lo(.Ltmp2)
----

NOTE: Although the generated code is technically position independent, it's not
Expand All @@ -118,7 +133,7 @@ This model is similar to the medium any code model, but uses the
# Calculate address of a local symbol
.Ltmp2: auipc a0, %pcrel_hi(symbol)
addi a0, a0, %pcrel_lo(.Ltmp2)
addi[w] a0, a0, %pcrel_lo(.Ltmp2)
# Calculate address of non-local symbol
.Ltmp3: auipc a0, %got_pcrel_hi(symbol)
Expand Down Expand Up @@ -685,9 +700,11 @@ The following assembly and relocations show loading an absolute address:
[,asm]
----
lui a0, %hi(symbol) # R_RISCV_HI20 (symbol)
addi a0, a0, %lo(symbol) # R_RISCV_LO12_I (symbol)
addi[w] a0, a0, %lo(symbol) # R_RISCV_LO12_I (symbol)
----

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

A symbol can be loaded in multiple fragments using different addends, where
multiple instructions associated with `R_RISCV_LO12_I`/`R_RISCV_LO12_S` share a
single `R_RISCV_HI20`. The HI20 values for the multiple fragments must be
Expand Down Expand Up @@ -738,12 +755,14 @@ in the PLT occupies two 16 byte entries:
sub t1, t1, t3 # shifted .got.plt offset + hdr size + 12
l[w|d] t3, %pcrel_lo(1b)(t2) # _dl_runtime_resolve
addi t1, t1, -(hdr size + 12) # shifted .got.plt offset
addi t0, t2, %pcrel_lo(1b) # &.got.plt
addi[w] t0, t2, %pcrel_lo(1b) # &.got.plt
srli t1, t1, log2(16/PTRSIZE) # .got.plt offset
l[w|d] t0, PTRSIZE(t0) # link map
jr t3
----

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

Subsequent function entry stubs in the PLT take up 16 bytes and load a
function pointer from the GOT. On the first call to a function, the
entry redirects to the first PLT entry which calls `_dl_runtime_resolve`
Expand Down Expand Up @@ -972,7 +991,7 @@ relocations are in comments.
[,asm]
----
lui a5,%tprel_hi(i) # R_RISCV_TPREL_HI20 (symbol)
add a5,a5,tp,%tprel_add(i) # R_RISCV_TPREL_ADD (symbol)
add[w] a5,a5,tp,%tprel_add(i) # R_RISCV_TPREL_ADD (symbol)
lw t0,%tprel_lo(i)(a5) # R_RISCV_TPREL_LO12_I (symbol)
addi t0,t0,1
sw t0,%tprel_lo(i)(a5) # R_RISCV_TPREL_LO12_S (symbol)
Expand All @@ -981,6 +1000,8 @@ relocations are in comments.
The `%tprel_add` assembler function does not return a value and is used purely
to associate the `R_RISCV_TPREL_ADD` relocation with the `add` instruction.

NOTE: `add` is for ILP32* and LP64* ABIs. `addw` is for RV64ILP32* ABIs.

==== Initial Exec

Initial exec is is a form of static thread local storage that can be used in
Expand All @@ -998,12 +1019,14 @@ Example assembler load and store of a thread local variable `i` using the
[,asm]
----
la.tls.ie a5,i
add a5,a5,tp
add[w] a5,a5,tp
lw t0,0(a5)
addi t0,t0,1
sw t0,0(a5)
----

NOTE: `add` is for ILP32* and LP64* ABIs. `addw` is for RV64ILP32* ABIs.

The assembler pseudoinstruction:

[,asm]
Expand Down Expand Up @@ -1057,11 +1080,13 @@ expands to the following assembly instructions and relocations:
----
label:
auipc a0,0 # R_RISCV_TLS_GD_HI20 (symbol)
addi a0,a0,0 # R_RISCV_PCREL_LO12_I (label)
addi[w] a0,a0,0 # R_RISCV_PCREL_LO12_I (label)
----

In the Global Dynamic model, the runtime library provides the `__tls_get_addr` function:

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

[,c]
----
extern void *__tls_get_addr (tls_index *ti);
Expand Down Expand Up @@ -1113,7 +1138,7 @@ assembler functions. The emitted relocations are in the comments.
label:
auipc tX, %tlsdesc_hi(symbol) // R_RISCV_TLSDESC_HI20 (symbol)
lw tY, tX, %tlsdesc_load_lo(label) // R_RISCV_TLSDESC_LOAD_LO12 (label)
addi a0, tX, %tlsdesc_add_lo(label) // R_RISCV_TLSDESC_ADD_LO12 (label)
addi[w] a0, tX, %tlsdesc_add_lo(label)// R_RISCV_TLSDESC_ADD_LO12 (label)
jalr t0, tY, %tlsdesc_call(label) // R_RISCV_TLSDESC_CALL (label)
----

Expand All @@ -1127,6 +1152,8 @@ The linker can use the relocations to recognize the sequence and to perform rela
- Instructions outside the sequence that do not clobber the registers used within the sequence may be inserted in-between the instructions of the sequence (known as instruction scheduling).
- Instructions in the sequence with no data dependency may be reordered. In the preceding example, the only instructions that can be reordered are `lw` and `addi`.

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

=== Sections

==== Section Types
Expand Down Expand Up @@ -1765,7 +1792,7 @@ NOTE: Tag_RISCV_x3_reg_usage is treated as 0 if it is not present.
removed if the symbol is absolute.

- The instruction or instructions associated with `R_RISCV_PCREL_LO12_I`
can be rewritten to either `c.li` or `addi` to materialize the symbol's
can be rewritten to either `c.li` or `addi` or `addiw` to materialize the symbol's
address directly in a register.

- If this relaxation eliminates all references to the symbol's GOT slot,
Expand Down Expand Up @@ -1795,17 +1822,19 @@ to use `c.li`):

[,asm]
----
addi tY, zero, <symbol-value>
addi[w] tY, zero, <symbol-value>
----

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

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

==== Zero-page Relaxation

Target Relocation:: R_RISCV_HI20, R_RISCV_LO12_I, R_RISCV_LO12_S
Expand Down Expand Up @@ -1901,7 +1930,7 @@ Relaxation candidate:
[,asm]
----
lui t0, 0 # R_RISCV_TPREL_HI20 (symbol), R_RISCV_RELAX
add t0, t0, tp # R_RISCV_TPREL_ADD (symbol), R_RISCV_RELAX
add[w] t0, t0, tp # R_RISCV_TPREL_ADD (symbol), R_RISCV_RELAX
lw t1, 0(t0) # R_RISCV_TPREL_LO12_I (symbol), R_RISCV_RELAX
----
Relaxation result:
Expand All @@ -1911,6 +1940,8 @@ Relaxation result:
----
--

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

==== TLS Descriptors -> Initial Exec Relaxation

Target Relocation:: R_RISCV_TLSDESC_HI20, R_RISCV_TLSDESC_LOAD_LO12, R_RISCV_TLSDESC_ADD_LO12, R_RISCV_TLSDESC_CALL
Expand All @@ -1935,7 +1966,7 @@ Relaxation candidate (`tX` and `tY` can be any combination of two general purpos
label:
auipc tX, <hi> // R_RISCV_TLSDESC_HI20 (symbol), R_RISCV_RELAX
lw tY, tX, <lo> // R_RISCV_TLSDESC_LOAD_LO12 (label)
addi a0, tX, <lo> // R_RISCV_TLSDESC_ADD_LO12 (label)
addi[w] a0, tX, <lo>// R_RISCV_TLSDESC_ADD_LO12 (label)
jalr t0, tY // R_RISCV_TLSDESC_CALL (label)
----

Expand All @@ -1948,6 +1979,8 @@ Relaxation result:
----
--

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

==== TLS Descriptors -> Local Exec Relaxation

Target Relocation:: R_RISCV_TLSDESC_HI20, R_RISCV_TLSDESC_LOAD_LO12, R_RISCV_TLSDESC_ADD_LO12, R_RISCV_TLSDESC_CALL
Expand Down Expand Up @@ -1976,7 +2009,7 @@ Relaxation candidate (`tX` and `tY` can be any combination of two general purpos
label:
auipc tX, <hi> // R_RISCV_TLSDESC_HI20 (symbol), R_RISCV_RELAX
lw tY, tX, <lo> // R_RISCV_TLSDESC_LOAD_LO12 (label)
addi a0, tX, <lo> // R_RISCV_TLSDESC_ADD_LO12 (label)
addi[w] a0, tX, <lo>// R_RISCV_TLSDESC_ADD_LO12 (label)
jalr t0, tY // R_RISCV_TLSDESC_CALL (label)
----

Expand All @@ -1985,17 +2018,19 @@ Relaxation result (long form):
[,asm]
----
lui a0, <tp-offset-for-symbol-hi>
addi a0, a0, <tp-offset-for-symbol-lo>
addi[w] a0, a0, <tp-offset-for-symbol-lo>
----

Relaxation result (short form):

[,asm]
----
addi a0, zero, <tp-offset-for-symbol>
addi[w] a0, zero, <tp-offset-for-symbol>
----
--

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

==== Table Jump Relaxation

Target Relocation::: R_RISCV_CALL, R_RISCV_CALL_PLT, R_RISCV_JAL.
Expand Down Expand Up @@ -2067,10 +2102,12 @@ instructions. It is recommended to initialize `jvt` CSR immediately after
----
# Recommended way to initialize the jvt CSR.
1: auipc a0, %pcrel_hi(__jvt_base$)
addi a0, a0, %pcrel_lo(1b)
addi[w] a0, a0, %pcrel_lo(1b)
csrw jvt, a0
----

NOTE: `addi` is for ILP32* and LP64* ABIs. `addiw` is for RV64ILP32* ABIs.

[bibliography]
== References

Expand Down

0 comments on commit c6e6e39

Please sign in to comment.