diff --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp --- a/lld/ELF/Arch/PPC64.cpp +++ b/lld/ELF/Arch/PPC64.cpp @@ -899,7 +899,7 @@ } bool PPC64::needsThunk(RelExpr expr, RelType type, const InputFile *file, - uint64_t branchAddr, const Symbol &s, int64_t /*a*/) const { + uint64_t branchAddr, const Symbol &s, int64_t a) const { if (type != R_PPC64_REL14 && type != R_PPC64_REL24) return false; @@ -916,7 +916,7 @@ // a range-extending thunk. // See the comment in getRelocTargetVA() about R_PPC64_CALL. return !inBranchRange(type, branchAddr, - s.getVA() + + s.getVA(a) + getPPC64GlobalEntryToLocalEntryOffset(s.stOther)); } diff --git a/lld/ELF/Relocations.cpp b/lld/ELF/Relocations.cpp --- a/lld/ELF/Relocations.cpp +++ b/lld/ELF/Relocations.cpp @@ -1818,7 +1818,7 @@ return true; rel.sym = &t->destination; // TODO Restore addend on all targets. - if (config->emachine == EM_AARCH64) + if (config->emachine == EM_AARCH64 || config->emachine == EM_PPC64) rel.addend = t->addend; if (rel.sym->isInPlt()) rel.expr = toPlt(rel.expr); @@ -1897,12 +1897,14 @@ rel.sym = t->getThunkTargetSym(); rel.expr = fromPlt(rel.expr); - // On AArch64, a jump/call relocation may be encoded as STT_SECTION - // + non-zero addend, clear the addend after redirection. + // On AArch64 and PPC64, a jump/call relocation may be encoded as + // STT_SECTION + non-zero addend, clear the addend after + // redirection. // // The addend of R_PPC_PLTREL24 should be ignored after changing to // R_PC. if (config->emachine == EM_AARCH64 || + config->emachine == EM_PPC64 || (config->emachine == EM_PPC && rel.type == R_PPC_PLTREL24)) rel.addend = 0; } diff --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h --- a/lld/ELF/Symbols.h +++ b/lld/ELF/Symbols.h @@ -87,9 +87,6 @@ // Version definition index. uint16_t versionId; - // An index into the .branch_lt section on PPC64. - uint16_t ppc64BranchltIndex = -1; - // Symbol binding. This is not overwritten by replace() to track // changes during resolution. In particular: // - An undefined weak is still weak when it resolves to a shared library. @@ -181,7 +178,6 @@ bool isInGot() const { return gotIndex != -1U; } bool isInPlt() const { return pltIndex != -1U; } - bool isInPPC64Branchlt() const { return ppc64BranchltIndex != 0xffff; } uint64_t getVA(int64_t addend = 0) const; @@ -190,8 +186,6 @@ uint64_t getGotPltOffset() const; uint64_t getGotPltVA() const; uint64_t getPltVA() const; - uint64_t getPPC64LongBranchTableVA() const; - uint64_t getPPC64LongBranchOffset() const; uint64_t getSize() const; OutputSection *getOutputSection() const; diff --git a/lld/ELF/Symbols.cpp b/lld/ELF/Symbols.cpp --- a/lld/ELF/Symbols.cpp +++ b/lld/ELF/Symbols.cpp @@ -162,11 +162,6 @@ return (pltIndex + target->gotPltHeaderEntriesNum) * config->wordsize; } -uint64_t Symbol::getPPC64LongBranchOffset() const { - assert(ppc64BranchltIndex != 0xffff); - return ppc64BranchltIndex * config->wordsize; -} - uint64_t Symbol::getPltVA() const { PltSection *plt = isInIplt ? in.iplt : in.plt; uint64_t outVA = @@ -179,12 +174,6 @@ return outVA; } -uint64_t Symbol::getPPC64LongBranchTableVA() const { - assert(ppc64BranchltIndex != 0xffff); - return in.ppc64LongBranchTarget->getVA() + - ppc64BranchltIndex * config->wordsize; -} - uint64_t Symbol::getSize() const { if (const auto *dr = dyn_cast(this)) return dr->size; diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h --- a/lld/ELF/SyntheticSections.h +++ b/lld/ELF/SyntheticSections.h @@ -1062,14 +1062,16 @@ class PPC64LongBranchTargetSection final : public SyntheticSection { public: PPC64LongBranchTargetSection(); - void addEntry(Symbol &sym); + uint64_t getEntryVA(const Symbol *sym, int64_t addend); + llvm::Optional addEntry(const Symbol *sym, int64_t addend); size_t getSize() const override; void writeTo(uint8_t *buf) override; bool isNeeded() const override; void finalizeContents() override { finalized = true; } private: - std::vector entries; + std::vector> entries; + llvm::DenseMap, uint32_t> entry_index; bool finalized = false; }; diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3426,10 +3426,19 @@ config->isPic ? SHT_NOBITS : SHT_PROGBITS, 8, ".branch_lt") {} -void PPC64LongBranchTargetSection::addEntry(Symbol &sym) { - assert(sym.ppc64BranchltIndex == 0xffff); - sym.ppc64BranchltIndex = entries.size(); - entries.push_back(&sym); +uint64_t PPC64LongBranchTargetSection::getEntryVA(const Symbol *sym, + int64_t addend) { + return getVA() + entry_index.find({sym, addend})->second * 8; +} + +Optional PPC64LongBranchTargetSection::addEntry(const Symbol *sym, + int64_t addend) { + auto res = + entry_index.try_emplace(std::make_pair(sym, addend), entries.size()); + if (!res.second) + return None; + entries.emplace_back(sym, addend); + return res.first->second; } size_t PPC64LongBranchTargetSection::getSize() const { @@ -3443,12 +3452,14 @@ if (config->isPic) return; - for (const Symbol *sym : entries) { + for (auto entry : entries) { + const Symbol *sym = entry.first; + int64_t addend = entry.second; assert(sym->getVA()); // Need calls to branch to the local entry-point since a long-branch // must be a local-call. - write64(buf, - sym->getVA() + getPPC64GlobalEntryToLocalEntryOffset(sym->stOther)); + write64(buf, sym->getVA(addend) + + getPPC64GlobalEntryToLocalEntryOffset(sym->stOther)); buf += 8; } } diff --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp --- a/lld/ELF/Thunks.cpp +++ b/lld/ELF/Thunks.cpp @@ -288,29 +288,29 @@ void addSymbols(ThunkSection &isec) override; protected: - PPC64LongBranchThunk(Symbol &dest) : Thunk(dest, 0) {} + PPC64LongBranchThunk(Symbol &dest, int64_t addend) : Thunk(dest, addend) {} }; class PPC64PILongBranchThunk final : public PPC64LongBranchThunk { public: - PPC64PILongBranchThunk(Symbol &dest) : PPC64LongBranchThunk(dest) { + PPC64PILongBranchThunk(Symbol &dest, int64_t addend) + : PPC64LongBranchThunk(dest, addend) { assert(!dest.isPreemptible); - if (dest.isInPPC64Branchlt()) - return; - - in.ppc64LongBranchTarget->addEntry(dest); - mainPart->relaDyn->addReloc( - {target->relativeRel, in.ppc64LongBranchTarget, - dest.getPPC64LongBranchOffset(), true, &dest, - getPPC64GlobalEntryToLocalEntryOffset(dest.stOther)}); + if (Optional index = + in.ppc64LongBranchTarget->addEntry(&dest, addend)) { + mainPart->relaDyn->addReloc( + {target->relativeRel, in.ppc64LongBranchTarget, *index * UINT64_C(8), + true, &dest, + addend + getPPC64GlobalEntryToLocalEntryOffset(dest.stOther)}); + } } }; class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk { public: - PPC64PDLongBranchThunk(Symbol &dest) : PPC64LongBranchThunk(dest) { - if (!dest.isInPPC64Branchlt()) - in.ppc64LongBranchTarget->addEntry(dest); + PPC64PDLongBranchThunk(Symbol &dest, int64_t addend) + : PPC64LongBranchThunk(dest, addend) { + in.ppc64LongBranchTarget->addEntry(&dest, addend); } }; @@ -785,7 +785,8 @@ } void PPC64LongBranchThunk::writeTo(uint8_t *buf) { - int64_t offset = destination.getPPC64LongBranchTableVA() - getPPC64TocBase(); + int64_t offset = in.ppc64LongBranchTarget->getEntryVA(&destination, addend) - + getPPC64TocBase(); writePPCLoadAndBranch(buf, offset); } @@ -901,15 +902,15 @@ return make(isec, rel, s); } -static Thunk *addThunkPPC64(RelType type, Symbol &s) { +static Thunk *addThunkPPC64(RelType type, Symbol &s, int64_t a) { assert(type == R_PPC64_REL24 && "unexpected relocation type for thunk"); if (s.isInPlt()) return make(s); if (config->picThunk) - return make(s); + return make(s, a); - return make(s); + return make(s, a); } Thunk *addThunk(const InputSection &isec, Relocation &rel) { @@ -929,7 +930,7 @@ return addThunkPPC32(isec, rel, s); if (config->emachine == EM_PPC64) - return addThunkPPC64(rel.type, s); + return addThunkPPC64(rel.type, s, a); llvm_unreachable("add Thunk only supported for ARM, Mips and PowerPC"); } diff --git a/lld/test/ELF/ppc64-long-branch-pi.s b/lld/test/ELF/ppc64-long-branch-pi.s new file mode 100644 --- /dev/null +++ b/lld/test/ELF/ppc64-long-branch-pi.s @@ -0,0 +1,89 @@ +# REQUIRES: ppc +# RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t.o +# RUN: echo 'SECTIONS { \ +# RUN: .text_low 0x2000: { *(.text_low) } \ +# RUN: .text_high 0x2002000 : { *(.text_high) } \ +# RUN: }' > %t.script +# RUN: ld.lld -pie -T %t.script %t.o -o %t +# RUN: llvm-readelf -S %t | FileCheck --check-prefix=SEC-PIE %s +# RUN: llvm-readobj -r %t | FileCheck --check-prefix=RELOC %s +# RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s + +# RUN: ld.lld -shared -T %t.script %t.o -o %t.so +# RUN: llvm-readelf -S %t.so | FileCheck --check-prefix=SEC-SHARED %s +# RUN: llvm-objdump -d --no-show-raw-insn %t.so | FileCheck %s + +# SEC-PIE: Name Type Address Off Size ES Flg Lk Inf Al +# SEC-PIE: .got PROGBITS 00000000020020e0 20120e0 000008 00 WA 0 0 8 +# SEC-PIE: .branch_lt NOBITS 00000000020020f0 20120f0 000020 00 WA 0 0 8 + +# SEC-SHARED: Name Type Address Off Size ES Flg Lk Inf Al +# SEC-SHARED: .got PROGBITS 00000000020020d0 20120d0 000008 00 WA 0 0 8 +# SEC-SHARED: .branch_lt NOBITS 00000000020020e0 20120e0 000020 00 WA 0 0 8 + +# RELOC: .rela.dyn { +# RELOC-NEXT: 0x20020E8 R_PPC64_RELATIVE - 0x8000 +# RELOC-NEXT: 0x20020F0 R_PPC64_RELATIVE - 0x2002000 +# RELOC-NEXT: 0x20020F8 R_PPC64_RELATIVE - 0x2002008 +# RELOC-NEXT: 0x2002100 R_PPC64_RELATIVE - 0x200200C +# RELOC-NEXT: 0x2002108 R_PPC64_RELATIVE - 0x2000 +# RELOC-NEXT: } + +# CHECK: _start: +# CHECK-NEXT: 2000: bl .+16 +# CHECK-NEXT: bl .+33554428 +# CHECK-NEXT: bl .+24 +# CHECK-NEXT: bl .+36 + +## &.branch_lt[0] - .TOC. = .branch_lt - (.got+0x8000) = -32752 +# CHECK: __long_branch_: +# CHECK-NEXT: 2010: addis 12, 2, 0 +# CHECK-NEXT: ld 12, -32752(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr + +## &.branch_lt[1] - .TOC. = .branch_lt - (.got+0x8000) = -32744 +# CHECK: __long_branch_: +# CHECK-NEXT: 2020: addis 12, 2, 0 +# CHECK-NEXT: ld 12, -32744(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr + +## &.branch_lt[2] - .TOC. = .branch_lt - (.got+0x8000) = -32736 +# CHECK: __long_branch_: +# CHECK-NEXT: 2030: addis 12, 2, 0 +# CHECK-NEXT: ld 12, -32736(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr + +.section .text_low, "ax", %progbits +.globl _start +_start: +bl .text_high # Need a thunk +bl .text_high +bl .text_high+8 # Need a thunk +bl .text_high+0xc # Need a thunk + +# CHECK: high_target: +# CHECK-NEXT: 2002000: bl .-33554428 +# CHECK-NEXT: bl .-33554432 +# CHECK-NEXT: bl .+8 + +## &.branch_lt[3] - .TOC. = .branch_lt - (.got+0x8000) = -32728 +# CHECK: __long_branch_: +# CHECK-NEXT: 2002010: addis 12, 2, 0 +# CHECK-NEXT: ld 12, -32728(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr + +.section .text_high, "ax", %progbits +high_target: +bl .text_low+4 +bl .text_low+4 +bl .text_low # Need a thunk +blr + +## Force creation of .got +## The R_PPC64_RELATIVE makes sure .rela.dyn survives removeUnusedSyntheticSections. +.section .data +.quad .TOC.@tocbase diff --git a/lld/test/ELF/ppc64-long-branch.s b/lld/test/ELF/ppc64-long-branch.s --- a/lld/test/ELF/ppc64-long-branch.s +++ b/lld/test/ELF/ppc64-long-branch.s @@ -1,94 +1,82 @@ # REQUIRES: ppc +# RUN: echo 'SECTIONS { \ +# RUN: .text_low 0x2000: { *(.text_low) } \ +# RUN: .text_high 0x2002000 : { *(.text_high) } \ +# RUN: }' > %t.script -# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o -# RUN: ld.lld --no-toc-optimize -z separate-code %t.o -o %t -# RUN: llvm-nm %t | FileCheck --check-prefix=NM %s -# RUN: llvm-readelf -x .branch_lt %t | FileCheck %s -check-prefix=BRANCH-LE +# RUN: llvm-mc -filetype=obj -triple=ppc64le %s -o %t.o +# RUN: ld.lld -T %t.script %t.o -o %t +# RUN: llvm-readelf -S -r %t | FileCheck --check-prefix=SEC %s +# RUN: llvm-readelf -x .branch_lt %t | FileCheck --check-prefix=BRANCH-LE %s # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s -# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o -# RUN: ld.lld --no-toc-optimize -z separate-code %t.o -o %t -# RUN: llvm-nm %t | FileCheck --check-prefix=NM %s -# RUN: llvm-readelf -x .branch_lt %t | FileCheck %s -check-prefix=BRANCH-BE +# RUN: llvm-mc -filetype=obj -triple=ppc64 %s -o %t.o +# RUN: ld.lld -T %t.script %t.o -o %t +# RUN: llvm-readelf -S -r %t | FileCheck --check-prefix=SEC %s +# RUN: llvm-readelf -x .branch_lt %t | FileCheck --check-prefix=BRANCH-BE %s # RUN: llvm-objdump -d --no-show-raw-insn %t | FileCheck %s - .text - .abiversion 2 - .protected callee - .globl callee - .p2align 4 - .type callee,@function -callee: -.Lfunc_gep0: - addis 2, 12, .TOC.-.Lfunc_gep0@ha - addi 2, 2, .TOC.-.Lfunc_gep0@l -.Lfunc_lep0: - .localentry callee, .Lfunc_lep0-.Lfunc_gep0 - addis 4, 2, .LC0@toc@ha - ld 4, .LC0@toc@l(4) - lwz 3, 0(4) - blr +# SEC: Name Type Address Off Size ES Flg Lk Inf Al +# SEC: .got PROGBITS 0000000002002028 2002028 000008 00 WA 0 0 8 +# SEC: .branch_lt PROGBITS 0000000002002030 2002030 000018 00 WA 0 0 8 - .space 0x2000000 - - .protected _start - .global _start - .p2align 4 - .type _start,@function -_start: -.Lfunc_begin1: -.Lfunc_gep1: - addis 2, 12, .TOC.-.Lfunc_gep1@ha - addi 2, 2, .TOC.-.Lfunc_gep1@l -.Lfunc_lep1: - .localentry _start, .Lfunc_lep1-.Lfunc_gep1 - mflr 0 - std 0, 16(1) - stdu 1, -32(1) - bl callee - bl callee - addi 1, 1, 32 - ld 0, 16(1) - mtlr 0 - - .section .toc,"aw",@progbits -.LC0: - .tc a[TC],a +# SEC: There are no relocations in this file. +## high@localentry (high+8), .text_high+16 and .text_low+8 +# BRANCH-LE: 0x02002030 08200002 00000000 10200002 00000000 +# BRANCH-LE-NEXT: 0x02002040 08200000 00000000 +# BRANCH-BE: 0x02002030 00000000 02002008 00000000 02002010 +# BRANCH-BE-NEXT: 0x02002040 00000000 00002008 - .data - .type a,@object - .globl a - .p2align 2 -a: - .long 11 - .size a, 4 +# CHECK: _start: +# CHECK-NEXT: 2000: bl .+24 +# CHECK-NEXT: bl .+20 +# CHECK-NEXT: bl .+16 +# CHECK-NEXT: bl .+33554428 -# NM: 0000000012028000 d .TOC. - -# Without --toc-optimize, compute the address of .toc[0] first. .toc[0] stores -# the address of a. -# .TOC. - callee = 0x12030000 - 0x10010000 = (514<<16) - 32768 -# CHECK: callee: -# CHECK: 10010000: addis 2, 12, 514 -# CHECK: 10010004: addi 2, 2, -32768 -# CHECK: 10010008: addis 4, 2, 0 +## &.branch_lt[0] - .TOC. = .branch_lt - (.got+0x8000) = -32760 +# CHECK: __long_branch_high: +# CHECK-NEXT: 2018: addis 12, 2, 0 +# CHECK-NEXT: ld 12, -32760(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr -# __long_branch_callee - . = 0x12010050 - 0x12010034 = 20 -# __long_branch_callee is not a PLT call stub. Calling it does not need TOC -# restore, so it doesn't have to be followed by a nop. -# CHECK: _start: -# CHECK: 12010034: bl .+20 -# CHECK: 12010038: bl .+16 +## &.branch_lt[1] - .TOC. = .branch_lt - (.got+0x8000) = -32752 +# CHECK: __long_branch_: +# CHECK-NEXT: 2028: addis 12, 2, 0 +# CHECK-NEXT: ld 12, -32752(12) +# CHECK-NEXT: mtctr 12 +# CHECK-NEXT: bctr -# BRANCH-LE: section '.branch_lt': -# BRANCH-LE-NEXT: 0x12030018 08000110 00000000 -# BRANCH-BE: section '.branch_lt': -# BRANCH-BE-NEXT: 0x12030018 00000000 10010008 +.section .text_low, "ax", %progbits +.globl _start +_start: +bl high # Need a thunk +bl high # Need a thunk +bl high # Need a thunk +bl high +bl .text_high+16 # Need a thunk +blr -# .branch_lt - .TOC. = 0x12030018 - 0x12028000 = (1<<16) - 32744 -# CHECK: __long_branch_callee: -# CHECK-NEXT: 12010048: addis 12, 2, 1 +# CHECK: Disassembly of section .text_high: +# CHECK-EMPTY: +# CHECK-NEXT: high: +# CHECK-NEXT: 2002000: addis 2, 12, 1 +# CHECK-NEXT: addi 2, 2, -32728 +# CHECK-NEXT: bl .-33554432 +# CHECK-NEXT: bl .+12 +# CHECK: __long_branch_: +# CHECK-NEXT: 2002018: addis 12, 2, 0 # CHECK-NEXT: ld 12, -32744(12) # CHECK-NEXT: mtctr 12 # CHECK-NEXT: bctr + +.section .text_high, "ax", %progbits +.globl high +high: +addis 2, 12, .TOC.-high@ha +addi 2, 2, .TOC.-high@l +.localentry high, 8 +bl .text_low+8 +bl .text_low+8 # Need a thunk +blr diff --git a/lld/test/ELF/ppc64-shared-long_branch.s b/lld/test/ELF/ppc64-shared-long_branch.s deleted file mode 100644 --- a/lld/test/ELF/ppc64-shared-long_branch.s +++ /dev/null @@ -1,113 +0,0 @@ -# REQUIRES: ppc - -# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o -# RUN: ld.lld --no-toc-optimize -shared -z separate-code %t.o -o %t -# RUN: llvm-objdump -d -start-address=0x10000 -stop-address=0x10018 %t | FileCheck %s -check-prefix=CALLEE_DUMP -# RUN: llvm-objdump -d -start-address=0x2010020 -stop-address=0x2010070 %t | FileCheck %s -check-prefix=CALLER_DUMP -# RUN: llvm-readelf --sections %t | FileCheck %s -check-prefix=SECTIONS -# RUN: llvm-readelf --relocations %t | FileCheck %s -check-prefix=DYNRELOC - - -# _start calls protected function callee. Since callee is protected no plt stub -# is needed. The binary however has been padded out with space so that the call -# distance is further then a bl instrution can reach. - - .text - .abiversion 2 - .protected callee - .global callee - .p2align 4 - .type callee,@function -callee: -.Lfunc_gep0: - addis 2, 12, .TOC.-.Lfunc_gep0@ha - addi 2, 2, .TOC.-.Lfunc_gep0@l -.Lfunc_lep0: - .localentry callee, .Lfunc_lep0-.Lfunc_gep0 - addis 4, 2, .LC0@toc@ha - ld 4, .LC0@toc@l(4) - lwz 3, 0(4) - blr - - .space 0x2000000 - - .protected _start - .globl _start - .p2align 4 - .type _start,@function -_start: -.Lfunc_begin1: -.Lfunc_gep1: - addis 2, 12, .TOC.-.Lfunc_gep1@ha - addi 2, 2, .TOC.-.Lfunc_gep1@l -.Lfunc_lep1: - .localentry _start, .Lfunc_lep1-.Lfunc_gep1 - mflr 0 - std 0, 16(1) - stdu 1, -32(1) - bl callee - bl ext_callee - nop - addi 1, 1, 32 - ld 0, 16(1) - mtlr 0 - - addis 4, 2, .LC1@toc@ha - ld 4, .LC1@toc@l(4) - lwz 4, 0(4) - add 3, 3, 4 - blr - - - .section .toc,"aw",@progbits -.LC0: - .tc a[TC],a -.LC1: - .tc b[TC],b - - - .data - .type a,@object - .globl a - .p2align 2 -a: - .long 11 - .size a, 4 - - .type b,@object - .globl b - .p2align 2 -b: - .long 33 - .size b, 4 - -# Verify address of the callee -# CALLEE_DUMP: callee: -# CALLEE_DUMP: 10000: {{.*}} addis 2, 12, 514 -# CALLEE_DUMP: 10004: {{.*}} addi 2, 2, -32528 -# CALLEE_DUMP: 10008: {{.*}} addis 4, 2, 0 - -# Verify the address of _start, and the call to the long-branch thunk. -# CALLER_DUMP: _start: -# CALLER_DUMP: 2010020: {{.*}} addis 2, 12, 2 -# CALLER_DUMP: 2010038: {{.*}} bl .+56 - -## .branch_lt[0] - .TOC. = -# CALLER_DUMP: __long_branch_callee: -# CALLER_DUMP: 2010060: {{.*}} addis 12, 2, 1 -# CALLER_DUMP: 2010064: {{.*}} ld 12, -32712(12) -# CALLER_DUMP: 2010068: {{.*}} mtctr 12 -# CALLER_DUMP: 201006c: {{.*}} bctr - -# .got section is at address 0x20300f0 so TOC pointer points to 0x20400F0. -# .plt section has a 2 entry header and a single entry for the long branch. -# [Nr] Name Type Address Off Size -# SECTIONS: [10] .got PROGBITS 00000000020200f0 20200f0 000008 -# SECTIONS: [13] .plt NOBITS 0000000002030110 2020110 000018 -# SECTIONS: [14] .branch_lt NOBITS 0000000002030128 2020110 000008 - -# There is a relative dynamic relocation for (.plt + 16 bytes), with a base -# address equal to callees local entry point (0x10000 + 8). -# DYNRELOC: Relocation section '.rela.dyn' at offset 0x{{[0-9a-f]+}} contains 3 entries: -# DYNRELOC: Offset Info Type Symbol's Value -# DYNRELOC: 0000000002030128 0000000000000016 R_PPC64_RELATIVE 10008