Page MenuHomePhabricator

[LLD][ELF][AArch64] Add support for R_AARCH64_LD64_GOTPAGE_LO15 relocation
Needs ReviewPublic

Authored by zatrazz on Wed, Jan 13, 9:35 AM.

Details

Summary

It is not used by LLVM, but GCC might generates it when compiling
with -fpie, as indicated by PR#40357 [1].

The testcase depends on https://reviews.llvm.org/D94611 to parse
gotpage_lo15 and https://reviews.llvm.org/D94809 to set the correct
placement of _GLOBAL_OFFSET_TABLE_ as expected by gcc.

Besides the regression check, I build a llvm (clang;clang-tools-extra;
compiler-rt;lld) with -fpie and -DLLVM_ENABLE_PIC=OFF with
gcc9 with DLLVM_ENABLE_LLD=ON to check if the
R_AARCH64_LD64_GOTPAGE_LO15 is handled correctly on large
projects.

The resulted build generates about 445619
R_AARCH64_LD64_GOTPAGE_LO15 relocations and the resulting
llvm shows no regression on check-all.

[1] https://bugs.llvm.org/show_bug.cgi?id=40357

Diff Detail

Event Timeline

zatrazz created this revision.Wed, Jan 13, 9:35 AM
zatrazz requested review of this revision.Wed, Jan 13, 9:35 AM
Herald added a project: Restricted Project. · View Herald TranscriptWed, Jan 13, 9:35 AM
psmith added a subscriber: psmith.Thu, Jan 14, 8:10 AM

Thanks for working on this. It will be very useful for people using GCC yet using LLD as a linker on AArch64. Will try and take a look later today, if not then I should have some time tomorrow morning.

psmith added inline comments.Thu, Jan 14, 9:31 AM
lld/ELF/InputSection.cpp
708

I think that this should be

return getAArch64Page(sym.getGotVA() + a) - getAArch64Page(in.got->getVA());

From https://github.com/ARM-software/abi-aa/blob/master/aaelf64/aaelf64.rst the expression is: G(GDAT(S+A))-Page(GOT)
Where GOT is "GOT is the address of the Global Offset Table"
Page(p) will be the same as Page(GOT) for many entries close to the start of the GOT.

IIUC the intent is to get an offset from the base of the GOT so that the same register can hold the base of the GOT for the whole function.

adrp x0, _GLOBAL_OFFSET_TABLE_
ldr x1, [x0, #:gotpage_lo15:foo]
ldr x2, [x0, #:gotpage_lo15:bar]
lld/test/ELF/aarch64-gotpage.s
6

This particular test won't catch the case where Page(GOT) != Page(P). Perhaps something like a linker script that puts the GOT at the last 8-bytes of a page (I think .got is 8 byte aligned on AArch64)

.got (0x10000 - 8) : { *.got }

This would put the first entry in the same page as Page(GOT) but the second entry should be in the second page. This should be visible in the ldr disassembly.

I will update the patch, since it is incomplete and requires https://reviews.llvm.org/D94809 .

lld/ELF/InputSection.cpp
708

Indeed it misses the addend in the account. I am not sure if G() should be page aligned as well, the AArch64 ABI is only explict about Page() operation, gold at least does not seem to align it. I think the correct formula is in fact:

return sym.getGotVA() + a - getAArch64Page(in.got->getVA());
zatrazz updated this revision to Diff 317019.Fri, Jan 15, 10:33 AM
zatrazz edited the summary of this revision. (Show Details)

Patch updated from comments, main changes are:

  • Fixed getRelocTargetVA fomula.
  • Fixed some lint issue.
  • Add a got displacement on .got for the test.