[lld] c8f0d3e - [ELF][PPC64] Support long branch thunks with addends

Fangrui Song via llvm-commits llvm-commits at lists.llvm.org
Thu Dec 5 10:17:56 PST 2019


Author: Fangrui Song
Date: 2019-12-05T10:17:45-08:00
New Revision: c8f0d3e130d336f49c204b9ee317bf99be192a82

URL: https://github.com/llvm/llvm-project/commit/c8f0d3e130d336f49c204b9ee317bf99be192a82
DIFF: https://github.com/llvm/llvm-project/commit/c8f0d3e130d336f49c204b9ee317bf99be192a82.diff

LOG: [ELF][PPC64] Support long branch thunks with addends

Fixes PPC64 part of PR40438

  // clang -target ppc64le -c a.cc
  // .text.unlikely may be placed in a separate output section (via -z keep-text-section-prefix)
  // The distance between bar in .text.unlikely and foo in .text may be larger than 32MiB.
  static void foo() {}
  __attribute__((section(".text.unlikely"))) static int bar() { foo(); return 0; }
  __attribute__((used)) static int dummy = bar();

This patch makes such thunks with addends work for PPC64.

AArch64: .text -> `__AArch64ADRPThunk_ (adrp x16, ...; add x16, x16, ...; br x16)` -> target
PPC64: .text -> `__long_branch_ (addis 12, 2, ...; ld 12, ...(12); mtctr 12; bctr)` -> target

AArch64 can leverage ADRP to jump to the target directly, but PPC64
needs to load an address from .branch_lt . Before Power ISA v3.0, the
PC-relative ADDPCIS was not available. .branch_lt was invented to work
around the limitation.

Symbol::ppc64BranchltIndex is replaced by
PPC64LongBranchTargetSection::entry_index which take addends into
consideration.

The tests are rewritten: ppc64-long-branch.s tests -no-pie and
ppc64-long-branch-pi.s tests -pie and -shared.

Reviewed By: sfertile

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

Added: 
    lld/test/ELF/ppc64-long-branch-pi.s

Modified: 
    lld/ELF/Arch/PPC64.cpp
    lld/ELF/Relocations.cpp
    lld/ELF/Symbols.cpp
    lld/ELF/Symbols.h
    lld/ELF/SyntheticSections.cpp
    lld/ELF/SyntheticSections.h
    lld/ELF/Thunks.cpp
    lld/test/ELF/ppc64-long-branch.s

Removed: 
    lld/test/ELF/ppc64-shared-long_branch.s


################################################################################
diff  --git a/lld/ELF/Arch/PPC64.cpp b/lld/ELF/Arch/PPC64.cpp
index ed16974af867..41639fbc12b7 100644
--- a/lld/ELF/Arch/PPC64.cpp
+++ b/lld/ELF/Arch/PPC64.cpp
@@ -899,7 +899,7 @@ void PPC64::relocateOne(uint8_t *loc, RelType type, uint64_t val) const {
 }
 
 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 @@ bool PPC64::needsThunk(RelExpr expr, RelType type, const InputFile *file,
   // 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
index 2c020be063ee..82e0fdb0421a 100644
--- a/lld/ELF/Relocations.cpp
+++ b/lld/ELF/Relocations.cpp
@@ -1818,7 +1818,7 @@ bool ThunkCreator::normalizeExistingThunk(Relocation &rel, uint64_t src) {
       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 @@ bool ThunkCreator::createThunks(ArrayRef<OutputSection *> outputSections) {
             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.cpp b/lld/ELF/Symbols.cpp
index c0cba21cfe8d..cb5b52ee4e83 100644
--- a/lld/ELF/Symbols.cpp
+++ b/lld/ELF/Symbols.cpp
@@ -162,11 +162,6 @@ uint64_t Symbol::getGotPltOffset() const {
   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 @@ uint64_t Symbol::getPltVA() const {
   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<Defined>(this))
     return dr->size;

diff  --git a/lld/ELF/Symbols.h b/lld/ELF/Symbols.h
index 2d3c5892284b..59e80da9c630 100644
--- a/lld/ELF/Symbols.h
+++ b/lld/ELF/Symbols.h
@@ -87,9 +87,6 @@ class Symbol {
   // 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 @@ class Symbol {
 
   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 @@ class Symbol {
   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/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 5bf7949dab53..a8aabe75a180 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -3426,10 +3426,19 @@ PPC64LongBranchTargetSection::PPC64LongBranchTargetSection()
                        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<uint32_t> 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 @@ void PPC64LongBranchTargetSection::writeTo(uint8_t *buf) {
   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/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index b46dc83e3878..afd34bbbd8b3 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -1062,14 +1062,16 @@ class PPC32Got2Section final : public SyntheticSection {
 class PPC64LongBranchTargetSection final : public SyntheticSection {
 public:
   PPC64LongBranchTargetSection();
-  void addEntry(Symbol &sym);
+  uint64_t getEntryVA(const Symbol *sym, int64_t addend);
+  llvm::Optional<uint32_t> 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<const Symbol *> entries;
+  std::vector<std::pair<const Symbol *, int64_t>> entries;
+  llvm::DenseMap<std::pair<const Symbol *, int64_t>, uint32_t> entry_index;
   bool finalized = false;
 };
 

diff  --git a/lld/ELF/Thunks.cpp b/lld/ELF/Thunks.cpp
index 8d2cdba616a6..8d03c93f74bd 100644
--- a/lld/ELF/Thunks.cpp
+++ b/lld/ELF/Thunks.cpp
@@ -288,29 +288,29 @@ class PPC64LongBranchThunk : public Thunk {
   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<uint32_t> 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 PPC64PltCallStub::addSymbols(ThunkSection &isec) {
 }
 
 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 @@ static Thunk *addThunkPPC32(const InputSection &isec, const Relocation &rel,
   return make<PPC32PltCallStub>(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<PPC64PltCallStub>(s);
 
   if (config->picThunk)
-    return make<PPC64PILongBranchThunk>(s);
+    return make<PPC64PILongBranchThunk>(s, a);
 
-  return make<PPC64PDLongBranchThunk>(s);
+  return make<PPC64PDLongBranchThunk>(s, a);
 }
 
 Thunk *addThunk(const InputSection &isec, Relocation &rel) {
@@ -929,7 +930,7 @@ Thunk *addThunk(const InputSection &isec, Relocation &rel) {
     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
index 000000000000..8fe05e7ba600
--- /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. at tocbase

diff  --git a/lld/test/ELF/ppc64-long-branch.s b/lld/test/ELF/ppc64-long-branch.s
index 2a6f66dfbfcc..cd90d6f8f64c 100644
--- 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, 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
+# 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, 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 callee
-    addi 1, 1, 32
-    ld   0, 16(1)
-    mtlr 0
-
-        .section        .toc,"aw", at progbits
-.LC0:
-       .tc a[TC],a
+# SEC: There are no relocations in this file.
 
+## high at 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, at 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 at ha
+addi 2, 2, .TOC.-high at 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
index 93b26edc5e0d..000000000000
--- 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, 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, 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


        


More information about the llvm-commits mailing list