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

Reply via email to