[lld] r346877 - [PPC64] Long branch thunks.

Sean Fertile via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 14 09:56:43 PST 2018


Author: sfertile
Date: Wed Nov 14 09:56:43 2018
New Revision: 346877

URL: http://llvm.org/viewvc/llvm-project?rev=346877&view=rev
Log:
[PPC64] Long branch thunks.

On PowerPC64, when a function call offset is too large to encode in a call
instruction the address is stored in a table in the data segment. A thunk is
used to load the branch target address from the table relative to the
TOC-pointer and indirectly branch to the callee. When linking position-dependent
code the addresses are stored directly in the table, for position-independent
code the table is allocated and filled in at load time by the dynamic linker.

For position-independent code the branch targets could have gone in the .got.plt
but using the .branch_lt section for both position dependent and position
independent binaries keeps it consitent and helps keep this PPC64 specific logic
seperated from the target-independent code handling the .got.plt.

Differential Revision: https://reviews.llvm.org/D53408

Added:
    lld/trunk/test/ELF/ppc64-long-branch.s
    lld/trunk/test/ELF/ppc64-shared-long_branch.s
Modified:
    lld/trunk/ELF/Arch/PPC64.cpp
    lld/trunk/ELF/Relocations.cpp
    lld/trunk/ELF/Symbols.cpp
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/ELF/SyntheticSections.h
    lld/trunk/ELF/Thunks.cpp
    lld/trunk/ELF/Writer.cpp
    lld/trunk/test/ELF/basic-ppc64.s
    lld/trunk/test/ELF/basic64be.s
    lld/trunk/test/ELF/ppc64-call-reach.s

Modified: lld/trunk/ELF/Arch/PPC64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC64.cpp?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC64.cpp (original)
+++ lld/trunk/ELF/Arch/PPC64.cpp Wed Nov 14 09:56:43 2018
@@ -113,6 +113,7 @@ public:
   void writeGotHeader(uint8_t *Buf) const override;
   bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
                   uint64_t BranchAddr, const Symbol &S) const override;
+  bool inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const override;
   RelExpr adjustRelaxExpr(RelType Type, const uint8_t *Data,
                           RelExpr Expr) const override;
   void relaxTlsGdToIe(uint8_t *Loc, RelType Type, uint64_t Val) const override;
@@ -709,9 +710,28 @@ void PPC64::relocateOne(uint8_t *Loc, Re
 
 bool PPC64::needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
                        uint64_t BranchAddr, const Symbol &S) const {
-  // If a function is in the plt it needs to be called through
-  // a call stub.
-  return Type == R_PPC64_REL24 && S.isInPlt();
+  // The only call relocation we currently support is the REL24 type.
+  if (Type != R_PPC64_REL24)
+    return false;
+
+  // If a function is in the Plt it needs to be called with a call-stub.
+  if (S.isInPlt())
+    return true;
+
+  // If a symbol is a weak undefined and we are compiling an executable
+  // it doesn't need a range-extending thunk since it can't be called.
+  if (S.isUndefWeak() && !Config->Shared)
+    return false;
+
+  // If the offset exceeds the range of the branch type then it will need
+  // a range-extending thunk.
+  return !inBranchRange(Type, BranchAddr, S.getVA());
+}
+
+bool PPC64::inBranchRange(RelType Type, uint64_t Src, uint64_t Dst) const {
+  assert(Type == R_PPC64_REL24 && "Unexpected relocation type used in branch");
+  int64_t Offset = Dst - Src;
+  return isInt<26>(Offset);
 }
 
 RelExpr PPC64::adjustRelaxExpr(RelType Type, const uint8_t *Data,

Modified: lld/trunk/ELF/Relocations.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Relocations.cpp?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/ELF/Relocations.cpp (original)
+++ lld/trunk/ELF/Relocations.cpp Wed Nov 14 09:56:43 2018
@@ -489,6 +489,7 @@ static void replaceWithDefined(Symbol &S
   Sym.PltIndex = Old.PltIndex;
   Sym.GotIndex = Old.GotIndex;
   Sym.VerdefIndex = Old.VerdefIndex;
+  Sym.PPC64BranchltIndex = Old.PPC64BranchltIndex;
   Sym.IsPreemptible = true;
   Sym.ExportDynamic = true;
   Sym.IsUsedInRegularObj = true;

Modified: lld/trunk/ELF/Symbols.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.cpp?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.cpp (original)
+++ lld/trunk/ELF/Symbols.cpp Wed Nov 14 09:56:43 2018
@@ -138,6 +138,11 @@ uint64_t Symbol::getGotPltOffset() const
   return (PltIndex + Target->GotPltHeaderEntriesNum) * Target->GotPltEntrySize;
 }
 
+uint64_t Symbol::getPPC64LongBranchOffset() const {
+  assert(PPC64BranchltIndex != 0xffff);
+  return PPC64BranchltIndex * Target->GotPltEntrySize;
+}
+
 uint64_t Symbol::getPltVA() const {
   if (this->IsInIplt)
     return In.Iplt->getVA() + PltIndex * Target->PltEntrySize;
@@ -149,6 +154,12 @@ uint64_t Symbol::getPltOffset() const {
   return Target->getPltEntryOffset(PltIndex);
 }
 
+uint64_t Symbol::getPPC64LongBranchTableVA() const {
+  assert(PPC64BranchltIndex != 0xffff);
+  return In.PPC64LongBranchTarget->getVA() +
+         PPC64BranchltIndex * Target->GotPltEntrySize;
+}
+
 uint64_t Symbol::getSize() const {
   if (const auto *DR = dyn_cast<Defined>(this))
     return DR->Size;

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Wed Nov 14 09:56:43 2018
@@ -79,6 +79,7 @@ public:
   uint32_t DynsymIndex = 0;
   uint32_t GotIndex = -1;
   uint32_t PltIndex = -1;
+
   uint32_t GlobalDynIndex = -1;
 
   // This field is a index to the symbol's version definition.
@@ -87,6 +88,9 @@ public:
   // 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 replaceSymbol to track
   // changes during resolution. In particular:
   //  - An undefined weak is still weak when it resolves to a shared library.
@@ -159,6 +163,7 @@ public:
 
   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;
 
@@ -168,6 +173,8 @@ public:
   uint64_t getGotPltVA() const;
   uint64_t getPltVA() const;
   uint64_t getPltOffset() const;
+  uint64_t getPPC64LongBranchTableVA() const;
+  uint64_t getPPC64LongBranchOffset() const;
   uint64_t getSize() const;
   OutputSection *getOutputSection() const;
 

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Wed Nov 14 09:56:43 2018
@@ -3070,6 +3070,53 @@ bool ThunkSection::assignOffsets() {
   return Changed;
 }
 
+// If linking position-dependent code then the table will store the addresses
+// directly in the binary so the section has type SHT_PROGBITS. If linking
+// position-independent code the section has type SHT_NOBITS since it will be
+// allocated and filled in by the dynamic linker.
+PPC64LongBranchTargetSection::PPC64LongBranchTargetSection()
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+                       Config->Pic ? SHT_NOBITS : SHT_PROGBITS, 8,
+                       ".branch_lt") {}
+
+void PPC64LongBranchTargetSection::addEntry(Symbol &Sym) {
+  assert(Sym.PPC64BranchltIndex == 0xffff);
+  Sym.PPC64BranchltIndex = Entries.size();
+  Entries.push_back(&Sym);
+}
+
+size_t PPC64LongBranchTargetSection::getSize() const {
+  return Entries.size() * 8;
+}
+
+void PPC64LongBranchTargetSection::writeTo(uint8_t *Buf) {
+  assert(Target->GotPltEntrySize == 8);
+  // If linking non-pic we have the final addresses of the targets and they get
+  // written to the table directly. For pic the dynamic linker will allocate
+  // the section and fill it it.
+  if (Config->Pic)
+    return;
+
+  for (const Symbol *Sym : Entries) {
+    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));
+    Buf += Target->GotPltEntrySize;
+  }
+}
+
+bool PPC64LongBranchTargetSection::empty() const {
+  // `removeUnusedSyntheticSections()` is called before thunk allocation which
+  // is too early to determine if this section will be empty or not. We need
+  // Finalized to keep the section alive until after thunk creation. Finalized
+  // only gets set to true once `finalizeSections()` is called after thunk
+  // creation. Becuase of this, if we don't create any long-branch thunks we end
+  // up with an empty .branch_lt section in the binary.
+  return Finalized && Entries.empty();
+}
+
 InStruct elf::In;
 
 template GdbIndexSection *GdbIndexSection::create<ELF32LE>();

Modified: lld/trunk/ELF/SyntheticSections.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.h?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.h (original)
+++ lld/trunk/ELF/SyntheticSections.h Wed Nov 14 09:56:43 2018
@@ -964,6 +964,25 @@ private:
   size_t Size = 0;
 };
 
+// This section is used to store the addresses of functions that are called
+// in range-extending thunks on PowerPC64. When producing position dependant
+// code the addresses are link-time constants and the table is written out to
+// the binary. When producing position-dependant code the table is allocated and
+// filled in by the dynamic linker.
+class PPC64LongBranchTargetSection final : public SyntheticSection {
+public:
+  PPC64LongBranchTargetSection();
+  void addEntry(Symbol &Sym);
+  size_t getSize() const override;
+  void writeTo(uint8_t *Buf) override;
+  bool empty() const override;
+  void finalizeContents() override { Finalized = true; }
+
+private:
+  std::vector<const Symbol *> Entries;
+  bool Finalized = false;
+};
+
 InputSection *createInterpSection();
 MergeInputSection *createCommentSection();
 template <class ELFT> void splitSections();
@@ -990,6 +1009,7 @@ struct InStruct {
   GotSection *Got;
   GotPltSection *GotPlt;
   IgotPltSection *IgotPlt;
+  PPC64LongBranchTargetSection *PPC64LongBranchTarget;
   MipsGotSection *MipsGot;
   MipsRldMapSection *MipsRldMap;
   PltSection *Plt;

Modified: lld/trunk/ELF/Thunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Thunks.cpp?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/ELF/Thunks.cpp (original)
+++ lld/trunk/ELF/Thunks.cpp Wed Nov 14 09:56:43 2018
@@ -234,6 +234,46 @@ public:
   void addSymbols(ThunkSection &IS) override;
 };
 
+// A bl instruction uses a signed 24 bit offset, with an implicit 4 byte
+// alignment. This gives a possible 26 bits of 'reach'. If the call offset is
+// larger then that we need to emit a long-branch thunk. The target address
+// of the callee is stored in a table to be accessed TOC-relative. Since the
+// call must be local (a non-local call will have a PltCallStub instead) the
+// table stores the address of the callee's local entry point. For
+// position-independent code a corresponding relative dynamic relocation is
+// used.
+class PPC64LongBranchThunk : public Thunk {
+public:
+  uint32_t size() override { return 16; }
+  void writeTo(uint8_t *Buf) override;
+  void addSymbols(ThunkSection &IS) override;
+
+protected:
+  PPC64LongBranchThunk(Symbol &Dest) : Thunk(Dest) {}
+};
+
+class PPC64PILongBranchThunk final : public PPC64LongBranchThunk {
+public:
+  PPC64PILongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
+    assert(!Dest.IsPreemptible);
+    if (Dest.isInPPC64Branchlt())
+      return;
+
+    In.PPC64LongBranchTarget->addEntry(Dest);
+    In.RelaDyn->addReloc({Target->RelativeRel, In.PPC64LongBranchTarget,
+                          Dest.getPPC64LongBranchOffset(), true, &Dest,
+                          getPPC64GlobalEntryToLocalEntryOffset(Dest.StOther)});
+  }
+};
+
+class PPC64PDLongBranchThunk final : public PPC64LongBranchThunk {
+public:
+  PPC64PDLongBranchThunk(Symbol &Dest) : PPC64LongBranchThunk(Dest) {
+    if (!Dest.isInPPC64Branchlt())
+      In.PPC64LongBranchTarget->addEntry(Dest);
+  }
+};
+
 } // end anonymous namespace
 
 Defined *Thunk::addSymbol(StringRef Name, uint8_t Type, uint64_t Value,
@@ -573,17 +613,21 @@ InputSection *MicroMipsR6Thunk::getTarge
   return dyn_cast<InputSection>(DR.Section);
 }
 
+static void writePPCLoadAndBranch(uint8_t *Buf, int64_t Offset) {
+  uint16_t OffHa = (Offset + 0x8000) >> 16;
+  uint16_t OffLo = Offset & 0xffff;
+
+  write32(Buf + 0, 0x3d820000 | OffHa); // addis r12, r2, OffHa
+  write32(Buf + 4, 0xe98c0000 | OffLo); // ld    r12, OffLo(r12)
+  write32(Buf + 8, 0x7d8903a6);         // mtctr r12
+  write32(Buf + 12, 0x4e800420);        // bctr
+}
+
 void PPC64PltCallStub::writeTo(uint8_t *Buf) {
-  int64_t Off = Destination.getGotPltVA() - getPPC64TocBase();
-  // Need to add 0x8000 to offset to account for the low bits being signed.
-  uint16_t OffHa = (Off + 0x8000) >> 16;
-  uint16_t OffLo = Off;
-
-  write32(Buf +  0, 0xf8410018);          // std     r2,24(r1)
-  write32(Buf +  4, 0x3d820000 | OffHa);  // addis   r12,r2, X at plt@to at ha
-  write32(Buf +  8, 0xe98c0000 | OffLo);  // ld      r12,X at plt@toc at l(r12)
-  write32(Buf + 12, 0x7d8903a6);          // mtctr   r12
-  write32(Buf + 16, 0x4e800420);          // bctr
+  int64_t Offset = Destination.getGotPltVA() - getPPC64TocBase();
+  // Save the TOC pointer to the save-slot reserved in the call frame.
+  write32(Buf + 0, 0xf8410018); // std     r2,24(r1)
+  writePPCLoadAndBranch(Buf + 4, Offset);
 }
 
 void PPC64PltCallStub::addSymbols(ThunkSection &IS) {
@@ -592,6 +636,16 @@ void PPC64PltCallStub::addSymbols(ThunkS
   S->NeedsTocRestore = true;
 }
 
+void PPC64LongBranchThunk::writeTo(uint8_t *Buf) {
+  int64_t Offset = Destination.getPPC64LongBranchTableVA() - getPPC64TocBase();
+  writePPCLoadAndBranch(Buf, Offset);
+}
+
+void PPC64LongBranchThunk::addSymbols(ThunkSection &IS) {
+  addSymbol(Saver.save("__long_branch_" + Destination.getName()), STT_FUNC, 0,
+            IS);
+}
+
 Thunk::Thunk(Symbol &D) : Destination(D), Offset(0) {}
 
 Thunk::~Thunk() = default;
@@ -675,9 +729,14 @@ static Thunk *addThunkMips(RelType Type,
 }
 
 static Thunk *addThunkPPC64(RelType Type, Symbol &S) {
-  if (Type == R_PPC64_REL24)
+  assert(Type == R_PPC64_REL24 && "unexpected relocation type for thunk");
+  if (S.isInPlt())
     return make<PPC64PltCallStub>(S);
-  fatal("unexpected relocation type");
+
+  if (Config->Pic)
+    return make<PPC64PILongBranchThunk>(S);
+
+  return make<PPC64PDLongBranchThunk>(S);
 }
 
 Thunk *addThunk(RelType Type, Symbol &S) {

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Nov 14 09:56:43 2018
@@ -365,6 +365,11 @@ template <class ELFT> static void create
     Add(In.Got);
   }
 
+  if (Config->EMachine == EM_PPC64) {
+    In.PPC64LongBranchTarget = make<PPC64LongBranchTargetSection>();
+    Add(In.PPC64LongBranchTarget);
+  }
+
   In.GotPlt = make<GotPltSection>();
   Add(In.GotPlt);
   In.IgotPlt = make<IgotPltSection>();
@@ -1756,6 +1761,7 @@ template <class ELFT> void Writer<ELFT>:
 
   // maybeAddThunks may have added local symbols to the static symbol table.
   finalizeSynthetic(In.SymTab);
+  finalizeSynthetic(In.PPC64LongBranchTarget);
 
   // Fill other section headers. The dynamic table is finalized
   // at the end because some tags like RELSZ depend on result

Modified: lld/trunk/test/ELF/basic-ppc64.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/basic-ppc64.s?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/test/ELF/basic-ppc64.s (original)
+++ lld/trunk/test/ELF/basic-ppc64.s Wed Nov 14 09:56:43 2018
@@ -28,7 +28,7 @@
 // CHECK-NEXT:  Version: 1
 // CHECK-NEXT:  Entry: 0x10000
 // CHECK-NEXT:  ProgramHeaderOffset: 0x40
-// CHECK-NEXT:  SectionHeaderOffset:
+// CHECK-NEXT:  SectionHeaderOffset: 0x200F8
 // CHECK-NEXT:  Flags [ (0x2)
 // CHECK-NEXT:    0x2
 // CHECK-NEXT:  ]
@@ -36,8 +36,8 @@
 // CHECK-NEXT:  ProgramHeaderEntrySize: 56
 // CHECK-NEXT:  ProgramHeaderCount: 7
 // CHECK-NEXT:  SectionHeaderEntrySize: 64
-// CHECK-NEXT:  SectionHeaderCount: 10
-// CHECK-NEXT:  StringTableSectionIndex: 8
+// CHECK-NEXT:  SectionHeaderCount: 11
+// CHECK-NEXT:  StringTableSectionIndex: 9
 // CHECK-NEXT:}
 // CHECK-NEXT:Sections [
 // CHECK-NEXT:  Section {
@@ -156,7 +156,23 @@
 // CHECK-NEXT:  }
 // CHECK-NEXT:  Section {
 // CHECK-NEXT:    Index: 6
-// CHECK-NEXT:    Name: .comment (38)
+// CHECK-NEXT:    Name: .branch_lt (38)
+// CHECK-NEXT:    Type: SHT_NOBITS (0x8)
+// CHECK-NEXT:    Flags [ (0x3)
+// CHECK-NEXT:      SHF_ALLOC (0x2)
+// CHECK-NEXT:      SHF_WRITE (0x1)
+// CHECK-NEXT:    ]
+// CHECK-NEXT:    Address: 0x30000
+// CHECK-NEXT:    Offset: 0x20060
+// CHECK-NEXT:    Size: 0
+// CHECK-NEXT:    Link: 0
+// CHECK-NEXT:    Info: 0
+// CHECK-NEXT:    AddressAlignment: 8
+// CHECK-NEXT:    EntrySize: 0
+// CHECK-NEXT:  }
+// CHECK-NEXT:  Section {
+// CHECK-NEXT:    Index: 7
+// CHECK-NEXT:    Name: .comment (49)
 // CHECK-NEXT:    Type: SHT_PROGBITS (0x1)
 // CHECK-NEXT:    Flags [ (0x30)
 // CHECK-NEXT:      SHF_MERGE (0x10)
@@ -174,15 +190,15 @@
 // CHECK-NEXT:    )
 // CHECK-NEXT:  }
 // CHECK-NEXT:  Section {
-// CHECK-NEXT:    Index: 7
-// CHECK-NEXT:    Name: .symtab (47)
+// CHECK-NEXT:    Index: 8
+// CHECK-NEXT:    Name: .symtab (58)
 // CHECK-NEXT:    Type: SHT_SYMTAB (0x2)
 // CHECK-NEXT:    Flags [ (0x0)
 // CHECK-NEXT:    ]
 // CHECK-NEXT:    Address: 0x0
 // CHECK-NEXT:    Offset: 0x20068
 // CHECK-NEXT:    Size: 48
-// CHECK-NEXT:    Link: 9
+// CHECK-NEXT:    Link: 10
 // CHECK-NEXT:    Info: 2
 // CHECK-NEXT:    AddressAlignment: 8
 // CHECK-NEXT:    EntrySize: 24
@@ -193,14 +209,14 @@
 // CHECK-NEXT:    )
 // CHECK-NEXT:  }
 // CHECK-NEXT:  Section {
-// CHECK-NEXT:    Index: 8
-// CHECK-NEXT:    Name: .shstrtab (55)
+// CHECK-NEXT:    Index: 9
+// CHECK-NEXT:    Name: .shstrtab (66)
 // CHECK-NEXT:    Type: SHT_STRTAB (0x3)
 // CHECK-NEXT:    Flags [ (0x0)
 // CHECK-NEXT:    ]
 // CHECK-NEXT:    Address: 0x0
 // CHECK-NEXT:    Offset: 0x20098
-// CHECK-NEXT:    Size: 73
+// CHECK-NEXT:    Size: 84
 // CHECK-NEXT:    Link: 0
 // CHECK-NEXT:    Info: 0
 // CHECK-NEXT:    AddressAlignment: 1
@@ -208,19 +224,20 @@
 // CHECK-NEXT:    SectionData (
 // CHECK-NEXT:      0000: 002E6479 6E73796D 002E6861 7368002E  |..dynsym..hash..|
 // CHECK-NEXT:      0010: 64796E73 7472002E 74657874 002E6479  |dynstr..text..dy|
-// CHECK-NEXT:      0020: 6E616D69 63002E63 6F6D6D65 6E74002E  |namic..comment..|
-// CHECK-NEXT:      0030: 73796D74 6162002E 73687374 72746162  |symtab..shstrtab|
-// CHECK-NEXT:      0040: 002E7374 72746162 00                 |..strtab.|
+// CHECK-NEXT:      0020: 6E616D69 63002E62 72616E63 685F6C74  |namic..branch_lt|
+// CHECK-NEXT:      0030: 002E636F 6D6D656E 74002E73 796D7461  |..comment..symta|
+// CHECK-NEXT:      0040: 62002E73 68737472 74616200 2E737472  |b..shstrtab..str|
+// CHECK-NEXT:      0050: 74616200                             |tab.|
 // CHECK-NEXT:    )
 // CHECK-NEXT:  }
 // CHECK-NEXT:  Section {
-// CHECK-NEXT:    Index: 9
-// CHECK-NEXT:    Name: .strtab (65)
+// CHECK-NEXT:    Index: 10
+// CHECK-NEXT:    Name: .strtab (76)
 // CHECK-NEXT:    Type: SHT_STRTAB (0x3)
 // CHECK-NEXT:    Flags [ (0x0)
 // CHECK-NEXT:    ]
 // CHECK-NEXT:    Address: 0x0
-// CHECK-NEXT:    Offset: 0x200E1
+// CHECK-NEXT:    Offset: 0x200EC
 // CHECK-NEXT:    Size: 10
 // CHECK-NEXT:    Link: 0
 // CHECK-NEXT:    Info: 0
@@ -275,7 +292,7 @@
 // CHECK-NEXT:    VirtualAddress: 0x20000
 // CHECK-NEXT:    PhysicalAddress: 0x20000
 // CHECK-NEXT:    FileSize: 96
-// CHECK-NEXT:    MemSize: 96
+// CHECK-NEXT:    MemSize: 65536
 // CHECK-NEXT:    Flags [ (0x6)
 // CHECK-NEXT:      PF_R (0x4)
 // CHECK-NEXT:      PF_W (0x2)

Modified: lld/trunk/test/ELF/basic64be.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/basic64be.s?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/test/ELF/basic64be.s (original)
+++ lld/trunk/test/ELF/basic64be.s Wed Nov 14 09:56:43 2018
@@ -23,7 +23,7 @@
 # CHECK-NEXT:   Version: 1
 # CHECK-NEXT:   Entry: 0x10010000
 # CHECK-NEXT:   ProgramHeaderOffset: 0x40
-# CHECK-NEXT:   SectionHeaderOffset: 0x11050
+# CHECK-NEXT:   SectionHeaderOffset: 0x20058
 # CHECK-NEXT:   Flags [ (0x2)
 # CHECK-NEXT:     0x2
 # CHECK-NEXT:   ]
@@ -31,8 +31,8 @@
 # CHECK-NEXT:   ProgramHeaderEntrySize: 56
 # CHECK-NEXT:   ProgramHeaderCount: 4
 # CHECK-NEXT:   SectionHeaderEntrySize: 64
-# CHECK-NEXT:   SectionHeaderCount: 6
-# CHECK-NEXT:   StringTableSectionIndex: 4
+# CHECK-NEXT:   SectionHeaderCount: 7
+# CHECK-NEXT:   StringTableSectionIndex: 5
 # CHECK-NEXT: }
 # CHECK-NEXT: Sections [
 # CHECK-NEXT:   Section {
@@ -72,14 +72,32 @@
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Section {
 # CHECK-NEXT:     Index: 2
-# CHECK-NEXT:     Name: .comment (7)
+# CHECK-NEXT:     Name: .branch_lt (7)
+# CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
+# CHECK-NEXT:     Flags [ (0x3)
+# CHECK-NEXT:       SHF_ALLOC (0x2)
+# CHECK-NEXT:       SHF_WRITE (0x1)
+# CHECK-NEXT:     ]
+# CHECK-NEXT:     Address: 0x10020000
+# CHECK-NEXT:     Offset: 0x20000
+# CHECK-NEXT:     Size: 0
+# CHECK-NEXT:     Link: 0
+# CHECK-NEXT:     Info: 0
+# CHECK-NEXT:     AddressAlignment: 8
+# CHECK-NEXT:     EntrySize: 0
+# CHECK-NEXT:     SectionData (
+# CHECK-NEXT:     )
+# CHECK-NEXT:   }
+# CHECK-NEXT:   Section {
+# CHECK-NEXT:     Index: 3
+# CHECK-NEXT:     Name: .comment (18)
 # CHECK-NEXT:     Type: SHT_PROGBITS (0x1)
 # CHECK-NEXT:     Flags [ (0x30)
 # CHECK-NEXT:       SHF_MERGE (0x10)
 # CHECK-NEXT:       SHF_STRINGS (0x20)
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address: 0x0
-# CHECK-NEXT:     Offset: 0x11000
+# CHECK-NEXT:     Offset: 0x20000
 # CHECK-NEXT:     Size: 8
 # CHECK-NEXT:     Link: 0
 # CHECK-NEXT:     Info: 0
@@ -90,15 +108,15 @@
 # CHECK-NEXT:     )
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Section {
-# CHECK-NEXT:     Index: 3
-# CHECK-NEXT:     Name: .symtab (16)
+# CHECK-NEXT:     Index: 4
+# CHECK-NEXT:     Name: .symtab (27)
 # CHECK-NEXT:     Type: SHT_SYMTAB (0x2)
 # CHECK-NEXT:     Flags [ (0x0)
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address: 0x0
-# CHECK-NEXT:     Offset: 0x11008
+# CHECK-NEXT:     Offset: 0x20008
 # CHECK-NEXT:     Size: 24
-# CHECK-NEXT:     Link: 5
+# CHECK-NEXT:     Link: 6
 # CHECK-NEXT:     Info: 1
 # CHECK-NEXT:     AddressAlignment: 8
 # CHECK-NEXT:     EntrySize: 24
@@ -108,32 +126,33 @@
 # CHECK-NEXT:     )
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Section {
-# CHECK-NEXT:     Index: 4
-# CHECK-NEXT:     Name: .shstrtab (24)
+# CHECK-NEXT:     Index: 5
+# CHECK-NEXT:     Name: .shstrtab (35)
 # CHECK-NEXT:     Type: SHT_STRTAB (0x3)
 # CHECK-NEXT:     Flags [ (0x0)
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address: 0x0
-# CHECK-NEXT:     Offset: 0x11020
-# CHECK-NEXT:     Size: 42
+# CHECK-NEXT:     Offset: 0x20020
+# CHECK-NEXT:     Size: 53
 # CHECK-NEXT:     Link: 0
 # CHECK-NEXT:     Info: 0
 # CHECK-NEXT:     AddressAlignment: 1
 # CHECK-NEXT:     EntrySize: 0
 # CHECK-NEXT:     SectionData (
-# CHECK-NEXT:       0000: 002E7465 7874002E 636F6D6D 656E7400  |..text..comment.|
-# CHECK-NEXT:       0010: 2E73796D 74616200 2E736873 74727461  |.symtab..shstrta|
-# CHECK-NEXT:       0020: 62002E73 74727461 6200               |b..strtab.|
+# CHECK-NEXT:       0000: 002E7465 7874002E 6272616E 63685F6C  |..text..branch_l|
+# CHECK-NEXT:       0010: 74002E63 6F6D6D65 6E74002E 73796D74  |t..comment..symt|
+# CHECK-NEXT:       0020: 6162002E 73687374 72746162 002E7374  |ab..shstrtab..st|
+# CHECK-NEXT:       0030: 72746162 00                          |rtab.|
 # CHECK-NEXT:     )
 # CHECK-NEXT:   }
 # CHECK-NEXT:   Section {
-# CHECK-NEXT:     Index: 5
-# CHECK-NEXT:     Name: .strtab (34)
+# CHECK-NEXT:     Index: 6
+# CHECK-NEXT:     Name: .strtab (45)
 # CHECK-NEXT:     Type: SHT_STRTAB (0x3)
 # CHECK-NEXT:     Flags [ (0x0)
 # CHECK-NEXT:     ]
 # CHECK-NEXT:     Address: 0x0
-# CHECK-NEXT:     Offset: 0x1104A
+# CHECK-NEXT:     Offset: 0x20055
 # CHECK-NEXT:     Size: 1
 # CHECK-NEXT:     Link: 0
 # CHECK-NEXT:     Info: 0
@@ -150,8 +169,8 @@
 # CHECK-NEXT:     Offset: 0x40
 # CHECK-NEXT:     VirtualAddress: 0x10000040
 # CHECK-NEXT:     PhysicalAddress: 0x10000040
-# CHECK-NEXT:     FileSize: 224
-# CHECK-NEXT:     MemSize: 224
+# CHECK-NEXT:     FileSize: 280
+# CHECK-NEXT:     MemSize: 280
 # CHECK-NEXT:     Flags [ (0x4)
 # CHECK-NEXT:       PF_R (0x4)
 # CHECK-NEXT:     ]
@@ -162,8 +181,8 @@
 # CHECK-NEXT:     Offset: 0x0
 # CHECK-NEXT:     VirtualAddress: 0x10000000
 # CHECK-NEXT:     PhysicalAddress: 0x10000000
-# CHECK-NEXT:     FileSize: 288
-# CHECK-NEXT:     MemSize: 288
+# CHECK-NEXT:     FileSize: 344
+# CHECK-NEXT:     MemSize: 344
 # CHECK-NEXT:     Flags [ (0x4)
 # CHECK-NEXT:       PF_R (0x4)
 # CHECK-NEXT:     ]

Modified: lld/trunk/test/ELF/ppc64-call-reach.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-call-reach.s?rev=346877&r1=346876&r2=346877&view=diff
==============================================================================
--- lld/trunk/test/ELF/ppc64-call-reach.s (original)
+++ lld/trunk/test/ELF/ppc64-call-reach.s Wed Nov 14 09:56:43 2018
@@ -10,8 +10,10 @@
 # RUN: ld.lld --defsym callee=0xE010014 --defsym tail_callee=0xE010024 \
 # RUN: %t.o -o %t
 # RUN: llvm-objdump -d %t | FileCheck --check-prefix=NEGOFFSET  %s
-# RUN: not ld.lld --defsym callee=0x12010018 --defsym tail_callee=0x12010028 \
-# RUN: %t.o -o %t 2>&1 | FileCheck --check-prefix=OVERFLOW %s
+# RUN: ld.lld --defsym callee=0x12010018 --defsym tail_callee=0x12010028 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=THUNK %s
+# RUN: llvm-readelf --sections %t | FileCheck --check-prefix=BRANCHLT %s
 # RUN: not ld.lld --defsym callee=0x1001002D --defsym tail_callee=0x1001002F \
 # RUN: %t.o -o %t 2>&1 | FileCheck --check-prefix=MISSALIGNED %s
 
@@ -25,14 +27,13 @@
 # RUN: ld.lld --defsym callee=0xE010014 --defsym tail_callee=0xE010024 \
 # RUN: %t.o -o %t
 # RUN: llvm-objdump -d %t | FileCheck --check-prefix=NEGOFFSET  %s
-# RUN: not ld.lld --defsym callee=0x12010018 --defsym tail_callee=0x12010028 \
-# RUN: %t.o -o %t 2>&1 | FileCheck --check-prefix=OVERFLOW %s
+# RUN: ld.lld --defsym callee=0x12010018 --defsym tail_callee=0x12010028 \
+# RUN: %t.o -o %t
+# RUN: llvm-objdump -d %t | FileCheck --check-prefix=THUNK %s
+# RUN: llvm-readelf --sections %t | FileCheck --check-prefix=BRANCHLT %s
 # RUN: not ld.lld --defsym callee=0x1001002D --defsym tail_callee=0x1001002F \
 # RUN: %t.o -o %t 2>&1 | FileCheck --check-prefix=MISSALIGNED %s
 
-# OVERFLOW: ld.lld: error: {{.*}}.o:(.text+0x14): relocation R_PPC64_REL24 out of range: 33554436 is not in [-33554432, 33554431]
-# OVERFLOW: ld.lld: error: {{.*}}.o:(.text+0x24): relocation R_PPC64_REL24 out of range: 33554436 is not in [-33554432, 33554431]
-
 # MISSALIGNED: ld.lld: error: {{.*}}.o:(.text+0x14): improper alignment for relocation R_PPC64_REL24: 0x19 is not aligned to 4 bytes
 # MISSALIGNED: ld.lld: error: {{.*}}.o:(.text+0x24): improper alignment for relocation R_PPC64_REL24: 0xB is not aligned to 4 bytes
 
@@ -64,3 +65,30 @@ test:
 # NEGOFFSET:  10010014: {{.*}}  bl .+33554432
 # NEGOFFSET:  10010024: {{.*}}  b  .+33554432
 
+# .branch_lt[0]
+# THUNK-LABEL: __long_branch_callee:
+# THUNK-NEXT: 10010000: {{.*}} addis 12, 2, -1
+# THUNK-NEXT:                  ld 12, -32768(12)
+# THUNK-NEXT:                  mtctr 12
+# THUNK-NEXT:                  bctr
+
+# .branch_lt[1]
+# THUNK-LABEL: __long_branch_tail_callee:
+# THUNK-NEXT: 10010010: {{.*}} addis 12, 2, -1
+# THUNK-NEXT:                  ld 12, -32760(12)
+# THUNK-NEXT:                  mtctr 12
+# THUNK-NEXT:                  bctr
+
+# Each call now branches to a thunk, and although it is printed as positive
+# the offset is interpreted as a signed 26 bit value so 67108812 is actually
+# -52.
+# THUNK-LABEL: test:
+# THUNK: 10010034: {{.*}}  bl .+67108812
+# THUNK: 10010044: {{.*}}  b .+67108812
+
+# The offset from the TOC to the .branch_lt section  is (-1 << 16) - 32768.
+#                Name             Type            Address          Off    Size
+# BRANCHLT:     .branch_lt        PROGBITS        0000000010020000 020000 000010
+# BRANCHLT:     .got              PROGBITS        0000000010030000 030000 000008
+# BRANCHLT-NOT: .plt
+

Added: lld/trunk/test/ELF/ppc64-long-branch.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-long-branch.s?rev=346877&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc64-long-branch.s (added)
+++ lld/trunk/test/ELF/ppc64-long-branch.s Wed Nov 14 09:56:43 2018
@@ -0,0 +1,121 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o
+# RUN: ld.lld  -shared %t2.o  -o %t3.so
+# RUN: ld.lld --no-toc-optimize %t.o %t3.so -o %t
+# RUN: llvm-objdump -d -start-address=0x10010000 -stop-address=0x10010018 %t | FileCheck %s -check-prefix=CALLEE_DUMP
+# RUN: llvm-objdump -d -start-address=0x12010020 -stop-address=0x12010084 %t | FileCheck %s -check-prefix=CALLER_DUMP
+# RUN: llvm-objdump -D -start-address=0x12020008 -stop-address=0x12020010 %t | FileCheck %s -check-prefix=BRANCH_LT_LE
+# RUN: llvm-readelf --sections %t | FileCheck %s -check-prefix=SECTIONS
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
+# RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/ppc64-func-global-entry.s -o %t2.o
+# RUN: ld.lld  -shared %t2.o  -o %t3.so
+# RUN: ld.lld --no-toc-optimize %t.o %t3.so -o %t
+# RUN: llvm-objdump -d -start-address=0x10010000 -stop-address=0x10010018 %t | FileCheck %s -check-prefix=CALLEE_DUMP
+# RUN: llvm-objdump -d -start-address=0x12010020 -stop-address=0x12010084 %t | FileCheck %s -check-prefix=CALLER_DUMP
+# RUN: llvm-objdump -D -start-address=0x12020008 -stop-address=0x12020010 %t | FileCheck %s -check-prefix=BRANCH_LT_BE
+# RUN: llvm-readelf --sections %t | FileCheck %s -check-prefix=SECTIONS
+
+        .text
+        .abiversion 2
+        .protected callee
+        .globl callee
+        .p2align 4
+        .type callee, at function
+callee:
+.Lfunc_gep0:
+    addis 2, 12, .TOC.-.Lfunc_gep0 at ha
+    addi 2, 2, .TOC.-.Lfunc_gep0 at l
+.Lfunc_lep0:
+    .localentry callee, .Lfunc_lep0-.Lfunc_gep0
+    addis 4, 2, .LC0 at toc@ha
+    ld    4, .LC0 at toc@l(4)
+    lwz   3, 0(4)
+    blr
+
+        .space 0x2000000
+
+        .protected _start
+        .global _start
+        .p2align 4
+        .type _start, at function
+_start:
+.Lfunc_begin1:
+.Lfunc_gep1:
+    addis 2, 12, .TOC.-.Lfunc_gep1 at ha
+    addi 2, 2, .TOC.-.Lfunc_gep1 at l
+.Lfunc_lep1:
+    .localentry	_start, .Lfunc_lep1-.Lfunc_gep1
+    mflr 0
+    std  0, 16(1)
+    stdu 1, -32(1)
+    bl callee
+    bl foo_external_diff
+    nop
+    addi 1, 1, 32
+    ld   0, 16(1)
+    mtlr 0
+
+    addis 4, 2, .LC1 at toc@ha
+    ld    4, .LC1 at toc@l(4)
+    lwz   4, 0(4)
+    add   3, 3, 4
+    blr
+
+
+        .section        .toc,"aw", at progbits
+.LC0:
+       .tc a[TC],a
+.LC1:
+       .tc b[TC],b
+
+
+        .data
+        .type a, at object
+        .globl a
+        .p2align 2
+a:
+        .long 11
+        .size a, 4
+
+        .type b, at object
+        .global b
+        .p2align 2
+b:
+        .long 33
+        .size b, 4
+
+# Verify address of the callee
+# CALLEE_DUMP: callee:
+# CALLEE_DUMP:   10010000:  {{.*}}  addis 2, 12, 515
+# CALLEE_DUMP:   10010004:  {{.*}}  addi 2, 2, -32544
+# CALLEE_DUMP:   10010008:  {{.*}}  addis 4, 2, 0
+
+# Verify the address of _start, and the call to the long-branch thunk.
+# CALLER_DUMP: _start:
+# CALLER_DUMP:   12010020:  {{.*}}  addis 2, 12, 3
+# CALLER_DUMP:   12010038:  {{.*}}  bl .+56
+
+# Verify the thunks contents: TOC-pointer + offset = .branch_lt[0]
+#                             0x120380e8  + (-2 << 16 + 32552) = 0x12020008
+# CALLER_DUMP: __long_branch_callee:
+# CALLER_DUMP:   12010060:  {{.*}}  addis 12, 2, -2
+# CALLER_DUMP:   12010064:  {{.*}}  ld 12, 32552(12)
+# CALLER_DUMP:   12010068:  {{.*}}  mtctr 12
+# CALLER_DUMP:   1201006c:  {{.*}}  bctr
+
+# BRANCH_LT_LE:     Disassembly of section .branch_lt:
+# BRANCH_LT_LE-NEXT:  .branch_lt:
+# BRANCH_LT_LE-NEXT:  12020008:   08 00 01 10
+# BRANCH_LT_LE-NEXT:  1202000c:   00 00 00 00
+
+# BRANCH_LT_BE:     Disassembly of section .branch_lt:
+# BRANCH_LT_BE-NEXT:  .branch_lt:
+# BRANCH_LT_BE-NEXT:  12020008:   00 00 00 00
+# BRANCH_LT_BE-NEXT:  1202000c:   10 01 00 08
+
+#            [Nr] Name        Type            Address          Off     Size
+# SECTIONS:  [ 9] .branch_lt  PROGBITS        0000000012020008 2020008 000008
+# SECTIONS:  [11] .got        PROGBITS        00000000120300e0 20300e0 000008

Added: lld/trunk/test/ELF/ppc64-shared-long_branch.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-shared-long_branch.s?rev=346877&view=auto
==============================================================================
--- lld/trunk/test/ELF/ppc64-shared-long_branch.s (added)
+++ lld/trunk/test/ELF/ppc64-shared-long_branch.s Wed Nov 14 09:56:43 2018
@@ -0,0 +1,114 @@
+# REQUIRES: ppc
+
+# RUN: llvm-mc -filetype=obj -triple=powerpc64le-unknown-linux %s -o %t.o
+# RUN: ld.lld --no-toc-optimize -shared %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, at function
+callee:
+.Lfunc_gep0:
+    addis 2, 12, .TOC.-.Lfunc_gep0 at ha
+    addi 2, 2, .TOC.-.Lfunc_gep0 at l
+.Lfunc_lep0:
+    .localentry callee, .Lfunc_lep0-.Lfunc_gep0
+    addis 4, 2, .LC0 at toc@ha
+    ld    4, .LC0 at toc@l(4)
+    lwz   3, 0(4)
+    blr
+
+        .space 0x2000000
+
+        .protected _start
+        .globl _start
+        .p2align 4
+        .type _start, at function
+_start:
+.Lfunc_begin1:
+.Lfunc_gep1:
+    addis 2, 12, .TOC.-.Lfunc_gep1 at ha
+    addi 2, 2, .TOC.-.Lfunc_gep1 at 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 at toc@ha
+    ld    4, .LC1 at toc@l(4)
+    lwz   4, 0(4)
+    add   3, 3, 4
+    blr
+
+
+        .section        .toc,"aw", at progbits
+.LC0:
+       .tc a[TC],a
+.LC1:
+       .tc b[TC],b
+
+
+        .data
+        .type a, at object
+        .globl a
+        .p2align 2
+a:
+        .long 11
+        .size a, 4
+
+        .type b, at 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, 515
+# 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, 3
+# CALLER_DUMP:   2010038:  {{.*}}  bl .+56
+
+# Verify the thunks contents: TOC-pointer + offset = .branch_lt[0]
+#                             0x20380F0   + 32552  = 0x2040018
+# CALLER_DUMP: __long_branch_callee:
+# CALLER_DUMP:   2010060:  {{.*}}  addis 12, 2, 0
+# CALLER_DUMP:   2010064:  {{.*}}  ld 12, 32552(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:  [11] .got        PROGBITS        00000000020300f0 20300f0 000008
+# SECTIONS:  [13] .plt        NOBITS          0000000002040000 2030108 000018
+# SECTIONS:  [14] .branch_lt  NOBITS          0000000002040018 2030108 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:    0000000002040018   0000000000000016 R_PPC64_RELATIVE   10008




More information about the llvm-commits mailing list