[lld] r331840 - [PPC64] Add lazy symbol resolution stubs.

Sean Fertile via llvm-commits llvm-commits at lists.llvm.org
Tue May 8 19:07:54 PDT 2018


Author: sfertile
Date: Tue May  8 19:07:53 2018
New Revision: 331840

URL: http://llvm.org/viewvc/llvm-project?rev=331840&view=rev
Log:
[PPC64] Add lazy symbol resolution stubs.

Adds support for .glink resolver stubs from the example implementation in the V2
ABI (Section 4.2.5.3. Procedure Linkage Table). The stubs are written to the
PltSection, and the sections are renamed to match the PPC64 ABI:
    .got.plt --> .plt    Type = SHT_NOBITS
    .plt     --> .glink

And adds the DT_PPC64_GLINK dynamic tag to the dynamic section when the plt is
not empty.

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

Modified:
    lld/trunk/ELF/Arch/PPC64.cpp
    lld/trunk/ELF/SyntheticSections.cpp
    lld/trunk/test/ELF/ppc64-dynamic-relocations.s
    lld/trunk/test/ELF/ppc64-ifunc.s
    lld/trunk/test/ELF/ppc64-plt-stub.s

Modified: lld/trunk/ELF/Arch/PPC64.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Arch/PPC64.cpp?rev=331840&r1=331839&r2=331840&view=diff
==============================================================================
--- lld/trunk/ELF/Arch/PPC64.cpp (original)
+++ lld/trunk/ELF/Arch/PPC64.cpp Tue May  8 19:07:53 2018
@@ -43,6 +43,9 @@ public:
   uint32_t calcEFlags() const override;
   RelExpr getRelExpr(RelType Type, const Symbol &S,
                      const uint8_t *Loc) const override;
+  void writePltHeader(uint8_t *Buf) const override;
+  void writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr, uint64_t PltEntryAddr,
+                int32_t Index, unsigned RelOff) const override;
   void relocateOne(uint8_t *Loc, RelType Type, uint64_t Val) const override;
   void writeGotHeader(uint8_t *Buf) const override;
   bool needsThunk(RelExpr Expr, RelType Type, const InputFile *File,
@@ -67,13 +70,13 @@ PPC64::PPC64() {
   PltRel = R_PPC64_JMP_SLOT;
   RelativeRel = R_PPC64_RELATIVE;
   GotEntrySize = 8;
+  PltEntrySize = 4;
   GotPltEntrySize = 8;
-  PltEntrySize = 0;
-  PltHeaderSize = 0;
   GotBaseSymInGotPlt = false;
   GotBaseSymOff = 0x8000;
   GotHeaderEntriesNum = 1;
   GotPltHeaderEntriesNum = 2;
+  PltHeaderSize = 60;
   NeedsThunks = true;
 
   // We need 64K pages (at least under glibc/Linux, the loader won't
@@ -170,6 +173,37 @@ void PPC64::writeGotHeader(uint8_t *Buf)
   write64(Buf, getPPC64TocBase());
 }
 
+void PPC64::writePltHeader(uint8_t *Buf) const {
+  // The generic resolver stub goes first.
+  write32(Buf +  0, 0x7c0802a6); // mflr r0
+  write32(Buf +  4, 0x429f0005); // bcl  20,4*cr7+so,8 <_glink+0x8>
+  write32(Buf +  8, 0x7d6802a6); // mflr r11
+  write32(Buf + 12, 0x7c0803a6); // mtlr r0
+  write32(Buf + 16, 0x7d8b6050); // subf r12, r11, r12
+  write32(Buf + 20, 0x380cffcc); // subi r0,r12,52
+  write32(Buf + 24, 0x7800f082); // srdi r0,r0,62,2
+  write32(Buf + 28, 0xe98b002c); // ld   r12,44(r11)
+  write32(Buf + 32, 0x7d6c5a14); // add  r11,r12,r11
+  write32(Buf + 36, 0xe98b0000); // ld   r12,0(r11)
+  write32(Buf + 40, 0xe96b0008); // ld   r11,8(r11)
+  write32(Buf + 44, 0x7d8903a6); // mtctr   r12
+  write32(Buf + 48, 0x4e800420); // bctr
+
+  // The 'bcl' instruction will set the link register to the address of the
+  // following instruction ('mflr r11'). Here we store the offset from that
+  // instruction  to the first entry in the GotPlt section.
+  int64_t GotPltOffset = InX::GotPlt->getVA() - (InX::Plt->getVA() + 8);
+  write64(Buf + 52, GotPltOffset);
+}
+
+void PPC64::writePlt(uint8_t *Buf, uint64_t GotPltEntryAddr,
+                     uint64_t PltEntryAddr, int32_t Index,
+                     unsigned RelOff) const {
+ int32_t Offset = PltHeaderSize + Index * PltEntrySize;
+ // bl __glink_PLTresolve
+ write32(Buf, 0x48000000 | ((-Offset) & 0x03FFFFFc));
+}
+
 static std::pair<RelType, uint64_t> toAddr16Rel(RelType Type, uint64_t Val) {
   uint64_t V = Val - PPC64TocOffset;
   switch (Type) {

Modified: lld/trunk/ELF/SyntheticSections.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/SyntheticSections.cpp?rev=331840&r1=331839&r2=331840&view=diff
==============================================================================
--- lld/trunk/ELF/SyntheticSections.cpp (original)
+++ lld/trunk/ELF/SyntheticSections.cpp Tue May  8 19:07:53 2018
@@ -874,9 +874,15 @@ void MipsGotSection::writeTo(uint8_t *Bu
   }
 }
 
+// On PowerPC the .plt section is used to hold the table of function addresses
+// instead of the .got.plt, and the type is SHT_NOBITS similar to a .bss
+// section. I don't know why we have a BSS style type for the section but it is
+// consitent across both 64-bit PowerPC ABIs as well as the 32-bit PowerPC ABI.
 GotPltSection::GotPltSection()
-    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
-                       Target->GotPltEntrySize, ".got.plt") {}
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+                       Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+                       Target->GotPltEntrySize,
+                       Config->EMachine == EM_PPC64 ? ".plt" : ".got.plt") {}
 
 void GotPltSection::addEntry(Symbol &Sym) {
   assert(Sym.PltIndex == Entries.size());
@@ -905,12 +911,25 @@ bool GotPltSection::empty() const {
          !(ElfSym::GlobalOffsetTable && Target->GotBaseSymInGotPlt);
 }
 
-// On ARM the IgotPltSection is part of the GotSection, on other Targets it is
-// part of the .got.plt
+static StringRef getIgotPltName() {
+  // On ARM the IgotPltSection is part of the GotSection.
+  if (Config->EMachine == EM_ARM)
+    return ".got";
+
+  // On PowerPC64 the GotPltSection is renamed to '.plt' so the IgotPltSection
+  // needs to be named the same.
+  if (Config->EMachine == EM_PPC64)
+    return ".plt";
+
+  return ".got.plt";
+}
+
+// On PowerPC64 the GotPltSection type is SHT_NOBITS so we have to follow suit
+// with the IgotPltSection.
 IgotPltSection::IgotPltSection()
-    : SyntheticSection(SHF_ALLOC | SHF_WRITE, SHT_PROGBITS,
-                       Target->GotPltEntrySize,
-                       Config->EMachine == EM_ARM ? ".got" : ".got.plt") {}
+    : SyntheticSection(SHF_ALLOC | SHF_WRITE,
+                       Config->EMachine == EM_PPC64 ? SHT_NOBITS : SHT_PROGBITS,
+                       Target->GotPltEntrySize, getIgotPltName()) {}
 
 void IgotPltSection::addEntry(Symbol &Sym) {
   Sym.IsInIgot = true;
@@ -1182,6 +1201,16 @@ template <class ELFT> void DynamicSectio
     }
   }
 
+  // Glink dynamic tag is required by the V2 abi if the plt section isn't empty.
+  if (Config->EMachine == EM_PPC64 && !InX::Plt->empty()) {
+    // The Glink tag points to 32 bytes before the first lazy symbol resolution
+    // stub, which starts directly after the header.
+    Entries.push_back({DT_PPC64_GLINK, [=] {
+                         unsigned Offset = Target->PltHeaderSize - 32;
+                         return InX::Plt->getVA(0) + Offset;
+                       }});
+  }
+
   addInt(DT_NULL, 0);
 
   getParent()->Link = this->Link;
@@ -1899,8 +1928,11 @@ void HashTableSection::writeTo(uint8_t *
   }
 }
 
+// On PowerPC64 the lazy symbol resolvers go into the `global linkage table`
+// in the .glink section, rather then the typical .plt section.
 PltSection::PltSection(bool IsIplt)
-    : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16, ".plt"),
+    : SyntheticSection(SHF_ALLOC | SHF_EXECINSTR, SHT_PROGBITS, 16,
+                       Config->EMachine == EM_PPC64 ? ".glink" : ".plt"),
       HeaderSize(IsIplt ? 0 : Target->PltHeaderSize), IsIplt(IsIplt) {
   // The PLT needs to be writable on SPARC as the dynamic linker will
   // modify the instructions in the PLT entries.

Modified: lld/trunk/test/ELF/ppc64-dynamic-relocations.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-dynamic-relocations.s?rev=331840&r1=331839&r2=331840&view=diff
==============================================================================
--- lld/trunk/test/ELF/ppc64-dynamic-relocations.s (original)
+++ lld/trunk/test/ELF/ppc64-dynamic-relocations.s Tue May  8 19:07:53 2018
@@ -5,7 +5,7 @@
 // RUN: ld.lld -shared %t2.o -o %t2.so
 // RUN: ld.lld %t.o %t2.so -o %t
 // RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
-// RUN: llvm-objdump -D %t | FileCheck --check-prefix=DIS %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s
 // RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
 
 // RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
@@ -13,29 +13,23 @@
 // RUN: ld.lld -shared %t2.o -o %t2.so
 // RUN: ld.lld %t.o %t2.so -o %t
 // RUN: llvm-readobj -dyn-relocations %t | FileCheck %s
-// RUN: llvm-objdump -D %t | FileCheck --check-prefix=DIS %s
+// RUN: llvm-objdump --section-headers %t | FileCheck --check-prefix=DIS %s
 // RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
 
 
 // The dynamic relocation for foo should point to 16 bytes past the start of
-// the .got.plt section.
+// the .plt section.
 // CHECK: Dynamic Relocations {
-// CHECK-NEXT:    0x10020010 R_PPC64_JMP_SLOT foo 0x0
+// CHECK-NEXT:    0x10030010 R_PPC64_JMP_SLOT foo 0x0
 
 // There should be 2 reserved doublewords before the first entry. The dynamic
 // linker will fill those in with the address of the resolver entry point and
 // the dynamic object identifier.
-// DIS: Disassembly of section .got.plt:
-// DIS-NEXT:  .got.plt:
-// DIS-NEXT: 10020000:       00 00 00 00  <unknown>
-// DIS-NEXT: 10020004:       00 00 00 00  <unknown>
-// DIS-NEXT: 10020008:       00 00 00 00  <unknown>
-// DIS-NEXT: 1002000c:       00 00 00 00  <unknown>
-// DIS-NEXT: 10020010:       00 00 00 00  <unknown>
-// DIS-NEXT: 10020014:       00 00 00 00  <unknown>
+// DIS: Idx Name       Size      Address          Type
+// DIS:     .plt       00000018  0000000010030000 BSS
 
-// DT_PLTGOT should point to the start of the .got.plt section.
-// DT: 0x0000000000000003 PLTGOT               0x10020000
+// DT_PLTGOT should point to the start of the .plt section.
+// DT: 0x0000000000000003 PLTGOT               0x10030000
 
     .text
     .abiversion 2

Modified: lld/trunk/test/ELF/ppc64-ifunc.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-ifunc.s?rev=331840&r1=331839&r2=331840&view=diff
==============================================================================
--- lld/trunk/test/ELF/ppc64-ifunc.s (original)
+++ lld/trunk/test/ELF/ppc64-ifunc.s Tue May  8 19:07:53 2018
@@ -5,30 +5,32 @@
 # RUN: ld.lld -shared %t2.o -o %t2.so
 # RUN: ld.lld %t.o %t2.so -o %t
 # RUN: llvm-objdump -D %t | FileCheck %s
+# RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
 
 # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %s -o %t.o
 # RUN: llvm-mc -filetype=obj -triple=powerpc64-unknown-linux %p/Inputs/shared-ppc64.s -o %t2.o
 # RUN: ld.lld -shared %t2.o -o %t2.so
 # RUN: ld.lld %t.o %t2.so -o %t
 # RUN: llvm-objdump -D %t | FileCheck %s
+# RUN: llvm-readelf -dynamic-table %t | FileCheck --check-prefix=DT %s
 
 # CHECK: Disassembly of section .text:
 
-# Tocbase    + (-2 << 16) + 32576
-# 0x100380d0 + (-131072)  + 32576 = 0x10020010 (.got.plt[2])
+# Tocbase    + (0 << 16) + 32560
+# 0x100280e0 +  0        + 32560 = 0x10030010 (.plt[2])
 # CHECK: __plt_foo:
 # CHECK-NEXT:     std 2, 24(1)
-# CHECK-NEXT:     addis 12, 2, -2
-# CHECK-NEXT:     ld 12, 32576(12)
+# CHECK-NEXT:     addis 12, 2, 0
+# CHECK-NEXT:     ld 12, 32560(12)
 # CHECK-NEXT:     mtctr 12
 # CHECK-NEXT:     bctr
 
-# Tocbase    + (-2 << 16) + 32584
-# 0x100380d0 + (-131072)  + 32584 = 0x10020018  (.got.plt[3])
+# Tocbase    + (0 << 16)  +  32568
+# 0x100280e0 +  0          + 32568 = 0x1003018 (.plt[3])
 # CHECK: __plt_ifunc:
 # CHECK-NEXT:     std 2, 24(1)
-# CHECK-NEXT:     addis 12, 2, -2
-# CHECK-NEXT:     ld 12, 32584(12)
+# CHECK-NEXT:     addis 12, 2, 0
+# CHECK-NEXT:     ld 12, 32568(12)
 # CHECK-NEXT:     mtctr 12
 # CHECK-NEXT:     bctr
 
@@ -36,24 +38,21 @@
 # CHECK-NEXT: 10010028:  {{.*}} nop
 
 # CHECK: _start:
-# CHECK-NEXT:     addis 2, 12, 3
-# CHECK-NEXT:     addi 2, 2, -32604
+# CHECK-NEXT:     addis 2, 12, 2
+# CHECK-NEXT:     addi 2, 2, -32588
 # CHECK-NEXT:     bl .+67108812
 # CHECK-NEXT:     ld 2, 24(1)
 # CHECK-NEXT:     bl .+67108824
 # CHECK-NEXT:     ld 2, 24(1)
 
-# Address of .got.plt
-# CHECK:      Disassembly of section .got.plt:
-# CHECK-NEXT:   .got.plt:
-# CHECK-NEXT:   10020000:
-
-
 # Check tocbase
 # CHECK:       Disassembly of section .got:
 # CHECK-NEXT:    .got:
-# CHECK-NEXT:    100300d0:
+# CHECK-NEXT:    100200e0
 
+# Check .plt address
+# DT_PLTGOT should point to the start of the .plt section.
+# DT: 0x0000000000000003 PLTGOT 0x10030000
 
     .text
     .abiversion 2

Modified: lld/trunk/test/ELF/ppc64-plt-stub.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/ELF/ppc64-plt-stub.s?rev=331840&r1=331839&r2=331840&view=diff
==============================================================================
--- lld/trunk/test/ELF/ppc64-plt-stub.s (original)
+++ lld/trunk/test/ELF/ppc64-plt-stub.s Tue May  8 19:07:53 2018
@@ -15,8 +15,8 @@
 // CHECK:      Disassembly of section .text:
 // CHECK-NEXT: __plt_foo:
 // CHECK-NEXT:      std 2, 24(1)
-// CHECK-NEXT:      addis 12, 2, -2
-// CHECK-NEXT:      ld 12, 32576(12)
+// CHECK-NEXT:      addis 12, 2, 0
+// CHECK-NEXT:      ld 12, 32560(12)
 // CHECK-NEXT:      mtctr 12
 // CHECK-NEXT:      bctr
 




More information about the llvm-commits mailing list