-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[BOLT][AArch64] Symbolize ADRP after relaxation #131414
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -125,15 +125,39 @@ AArch64MCSymbolizer::adjustRelocation(const Relocation &Rel, | |
| // instruction pairs and will perform necessary adjustments. | ||
| ErrorOr<uint64_t> SymbolValue = BC.getSymbolValue(*Rel.Symbol); | ||
| assert(SymbolValue && "Symbol value should be set"); | ||
| (void)SymbolValue; | ||
|
|
||
| AdjustedRel.Symbol = BC.registerNameAtAddress("__BOLT_got_zero", 0, 0, 0); | ||
| AdjustedRel.Addend = Rel.Value; | ||
| const uint64_t SymbolPageAddr = *SymbolValue & ~0xfffULL; | ||
|
|
||
| // Check if defined symbol and GOT are on the same page. If they are not, | ||
| // disambiguate the operand. | ||
| if (BC.MIB->isADRP(Inst) && Rel.Addend == 0 && | ||
| SymbolPageAddr == Rel.Value && | ||
| !isPageAddressValidForGOT(SymbolPageAddr)) { | ||
| AdjustedRel.Type = ELF::R_AARCH64_ADR_PREL_PG_HI21; | ||
| } else { | ||
| AdjustedRel.Symbol = BC.registerNameAtAddress("__BOLT_got_zero", 0, 0, 0); | ||
| AdjustedRel.Addend = Rel.Value; | ||
| } | ||
| } | ||
|
|
||
| return AdjustedRel; | ||
| } | ||
|
|
||
| bool AArch64MCSymbolizer::isPageAddressValidForGOT(uint64_t PageAddress) const { | ||
| assert(!(PageAddress & 0xfffULL) && "Page address not aligned at 4KB"); | ||
|
|
||
| ErrorOr<BinarySection &> GOT = | ||
| Function.getBinaryContext().getUniqueSectionByName(".got"); | ||
| if (!GOT || !GOT->getSize()) | ||
| return false; | ||
|
|
||
| const uint64_t GOTFirstPageAddress = GOT->getAddress() & ~0xfffULL; | ||
| const uint64_t GOTLastPageAddress = | ||
| (GOT->getAddress() + GOT->getSize() - 1) & ~0xfffULL; | ||
|
|
||
| return PageAddress >= GOTFirstPageAddress && | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if we can do this, the GOT doesn't have to be page-aligned. And in some rare cases ADRP might refer to a page with GOT, but not to GOT it self..
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the symbolizer-level conversion is only triggered when the address is guaranteed to not be in the GOT. There will be cases when the object will be on the same page as GOT in which case the symbolization will preserve the GOT reference and delegate the proper resolution to the
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @yota9, any further comments? If not, I'll merge. |
||
| PageAddress <= GOTLastPageAddress; | ||
| } | ||
|
|
||
| void AArch64MCSymbolizer::tryAddingPcLoadReferenceComment(raw_ostream &CStream, | ||
| int64_t Value, | ||
| uint64_t Address) {} | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| ## Check that BOLT symbolizer properly handles loads from GOT, including | ||
| ## instruction sequences changed/relaxed by the linker. | ||
|
|
||
| # RUN: split-file %s %t | ||
|
|
||
| # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %t/main.s \ | ||
| # RUN: -o %t/main.o | ||
| # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %t/near.s \ | ||
| # RUN: -o %t/near.o | ||
| # RUN: llvm-mc -filetype=obj -triple aarch64-unknown-unknown %t/far.s \ | ||
| # RUN: -o %t/far.o | ||
| # RUN: %clang %cflags %t/main.o %t/near.o %t/far.o -o %t/main.exe -Wl,-q -static | ||
| # RUN: llvm-bolt %t/main.exe -o %t/main.bolt --keep-nops --print-disasm \ | ||
| # RUN: --print-only=_start | FileCheck %s | ||
|
|
||
| #--- main.s | ||
|
|
||
| .text | ||
| .globl _start | ||
| .p2align 2 | ||
| .type _start, @function | ||
| # CHECK-LABEL: _start | ||
| _start: | ||
|
|
||
| ## Function address load relaxable into nop+adr. | ||
| # CHECK: nop | ||
| # CHECK-NEXT: adr x0, near | ||
| adrp x0, :got:near | ||
| ldr x0, [x0, :got_lo12:near] | ||
|
|
||
| ## Function address load relaxable into adrp+add. | ||
| # CHECK-NEXT: adrp x1, far | ||
| # CHECK-NEXT: add x1, x1, :lo12:far | ||
| adrp x1, :got:far | ||
| ldr x1, [x1, :got_lo12:far] | ||
|
|
||
| ## Non-relaxable due to the instruction in-between. | ||
| # CHECK-NEXT: adrp x2, __BOLT_got_zero | ||
| # CHECK-NEXT: nop | ||
| # CHECK-NEXT: ldr x2, [x2, :lo12:__BOLT_got_zero{{.*}}] | ||
| adrp x2, :got:near | ||
| nop | ||
| ldr x2, [x2, :got_lo12:near] | ||
|
|
||
| ## Load data object with local visibility. Relaxable into adrp+add. | ||
| # CHECK-NEXT: adrp x3, "local_far_data/1" | ||
| # CHECK-NEXT: add x3, x3, :lo12:"local_far_data/1" | ||
| adrp x3, :got:local_far_data | ||
| ldr x3, [x3, :got_lo12:local_far_data] | ||
|
|
||
| ## Global data reference relaxable into adrp+add. | ||
| # CHECK-NEXT: adrp x4, far_data | ||
| # CHECK-NEXT: add x4, x4, :lo12:far_data | ||
| adrp x4, :got:far_data | ||
| ldr x4, [x4, :got_lo12:far_data] | ||
|
|
||
| ret | ||
| .size _start, .-_start | ||
|
|
||
| .weak near | ||
| .weak far | ||
| .weak far_data | ||
|
|
||
| ## Data object separated by more than 1MB from _start. | ||
paschalis-mpeis marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| .data | ||
| .type local_far_data, @object | ||
| local_far_data: | ||
| .xword 0 | ||
| .size local_far_data, .-local_far_data | ||
|
|
||
| #--- near.s | ||
|
|
||
| .text | ||
| .globl near | ||
| .type near, @function | ||
| near: | ||
| ret | ||
| .size near, .-near | ||
|
|
||
| #--- far.s | ||
|
|
||
| .text | ||
|
|
||
| ## Insert 1MB of empty space to make objects after it unreachable by adr | ||
| ## instructions in _start. | ||
| .space 0x100000 | ||
|
|
||
| .globl far | ||
| .type far, @function | ||
| far: | ||
| ret | ||
| .size far, .-far | ||
|
|
||
| .data | ||
| .globl far_data | ||
| .type far_data, @object | ||
| far_data: | ||
| .xword 0 | ||
| .size far_data, .-far_data | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.