1

I have a symbol _symbol and need to load its absolute address. But if I write

lui t1, %hi(_symbol)
addi t1, t1, %lo(_symbol)

the linker complaints just like this

relocation R_RISCV_HI20 out of range: -2251799813160077 is not in [-524288, 524287]

My question is: how can I load the address of a symbol by ABSOLUTE addressing in RISC-V asm (without GOT, since there is no dynamic linker)?

A similar question is here: How can I load the absolute address of a symbol larger than 0x7FFFFFFF in RiscV64 assembly But the solution given above does not work for me, because the load address and the destination address are also very far (> 2^32) from each other.

Usamoi
  • 58
  • 2
  • 6
  • Did you try looking at compiler output, e.g. https://godbolt.org/z/359rf7PM1? RV64 GCC uses an `lla t1, symbol` pseudo-instruction with `-O3 -mcmodel=medany`, vs. `la` with `-fPIC`. Or RV64 clang uses a PC-relative load from the GOT with `-fPIC`. – Peter Cordes Jan 04 '22 at 09:44
  • @PeterCordes No. I need load a ABSOLTE address. – Usamoi Jan 04 '22 at 09:49
  • I don't know why using ABSOLUTE address is a must. However, if so, saving the address at a not so far memory location and using memory operating instruction, `ld`, is an option. – Wanghz Jan 04 '22 at 10:11
  • @Wanghz Because the load address of my program is not the same with that in the linker script, so I need to enable paging and use the absolute address of symbols in my program before entering the main. – Usamoi Jan 04 '22 at 10:26
  • The GOT holds absolute addresses. It's reachable with PC-relative addressing. But anyway, that's just *one* of the multiple options I mentioned. Do none of them assemble to 64-bit absolute? I guessed `-mcmodel=medany` would; it has to support large static arrays so static data can't be assumed to be in range for PC-relative directly. – Peter Cordes Jan 04 '22 at 10:34
  • 3
    32-bit ARM assemblers placed the address (a 32-bit word) as data after the code and loaded the 32-bit value using a PC-relative load instruction. You could do it the same way and place a 64-bit constant (the address) after the code. I have never worked with RISC-V, but the combination of `AUIPC` and `LD` should be able to load the 64-bit constant. – Martin Rosenau Jan 04 '22 at 14:16
  • @PeterCordes No. 1. Both `mcmodel=medany` and `mcmodel=large` make no difference, 2. bytes in .got are zeros maybe because I just simply `objcopy` to translate elf to binary. – Usamoi Jan 05 '22 at 03:41
  • Ok, the fact that you don't have a dynamic linker to fill GOT entries is probably something you should mention in your question. Future readers with a similar problem for large static data in a normal program under an OS might want to do it that way. But anyway, Martin's idea would still work: manually assemble a 64-bit absolute address as data somewhere near enough you can load it with `auipc` / `ld`. Otherwise IDK what strategy for constructing large addresses the RISC-V ABI assumes for its design of the relocations available. – Peter Cordes Jan 05 '22 at 03:45
  • Just to be clear, `-mcmodel=large` definitely won't help assembling existing asm. My suggestion was to compile a C function using that option, and look at what instructions the compiler used. – Peter Cordes Jan 05 '22 at 03:48
  • 1
    @MartinRosenau Yes, it works! Thank you! – Usamoi Jan 05 '22 at 04:40

1 Answers1

1

According to @MartinRosenau's suggestion: place a 64-bit constant (the address) after the code. The solution can be written as follows:

# Use load instruction get address of _symbol
ld t1, symbol_addr
jr t1
...
# A large pc for _symbol
_symbol:
    nop
    ...
.data
# symbol_addr equals to the address of _symbol
symbol_addr: .dowrd _symbol

The data symbol_addr will be calculated automatically as the address of _symbol, which maybe a large address, then use "ld" instruction to load the symbol_addr, register 't1' equals to symbol_addr and "jr" instruction will works.

sven
  • 86
  • 6