On Wed, 4 Sep 2024, Evgeny Karpov wrote:
Monday, September 4, 2024
Martin Storsjö <mar...@martin.st> wrote:
Let's consider the following example, when symbol is located at 3072.
1. Example without the fix
compilation time
adrp x0, (3072 + 256) & ~0xFFF // x0 = 0
add x0, x0, (3072 + 256) & 0xFFF // x0 = 3328
linking time when symbol is relocated with offset 896
adrp x0, (0 + 896) & ~0xFFF // x0 = 0
Why did the 3072 suddenly become 0 here?
The test case which will be compiled.
adrp x0, symbol + 256
add x0, x0, symbol + 256
The numbers which are presented in the example help to clarify relocation steps.
symbol is located at 3072.
compilation time
adrp x0, symbol + 256
90000000 adrp x0, 0
This is your first error.
As the symbol offset is 256, you will need to encode the offset "256" in
the instruction immediate field. Not "256 >> 12". This is the somewhat
non-obvious part here, but this is the only way symbol offsets can work.
This is how MS tools handle immediates in IMAGE_REL_ARM64_PAGEBASE_REL21,
and LLVM has replicated this bit.
See
https://github.com/llvm/llvm-project/commit/0b7bf7a2e3cb34086d6a05419319fd35ae8dd9a8#diff-502793e1256bca6339a09f5756111a947a2aeb5c600cdd22b2e1679db5ec48b0R162
for the case where I implemented this bit in LLVM.
add x0, x0, symbol + 256
91340000 add x0, x0, 3328
linking time when symbol is relocated with offset 896
compiled 90000000 adrp x0, 0
relocated 90000000 adrp x0, 0 // without change
((0 << 12) + 896) >> 12 = 0 // relocation calculation
This is the wrong calculation for how to apply a
IMAGE_REL_ARM64_PAGEBASE_REL21 relocation.
If the instruction in the object file has the immediate obj_imm, and the
instruction is at address instr_addr, the linker should update the
instruction, setting the immediate to ((symbol_addr + obj_imm) >> 12 -
instr_addr >> 12.
See
https://github.com/llvm/llvm-project/commit/38608c0975772513007ec08116a1a3fb6160722b
how this was implemented in LLD.
// Martin