[lld] r250110 - [ELF2] Allow PPC64 to add the TOC-restore after .plt-based relocations

Hal Finkel via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 12 14:19:18 PDT 2015


Author: hfinkel
Date: Mon Oct 12 16:19:18 2015
New Revision: 250110

URL: http://llvm.org/viewvc/llvm-project?rev=250110&view=rev
Log:
[ELF2] Allow PPC64 to add the TOC-restore after .plt-based relocations

Under the PPC64 ELF ABI, functions that might call into other modules (and,
thus, need to load a different TOC base value into %r2), need to restore the
old value after the call. The old value is saved by the .plt code, and the
caller only needs to include a nop instruction after the call, which the linker
will transform into a TOC restore if necessary.

In order to do this the relocation handler needs two things:

 1. It needs to know whether the call instruction it is modifying is targeting
    a .plt stub that will load a new TOC base value (necessitating a restore after
    the call).

 2. It needs to know where the buffer ends, so that it does not accidentally
    run off the end of the buffer when looking for the 'nop' instruction after the
    call.

Given these two pieces of information, we can insert the restore instruction in
place of the following nop when necessary.

Added:
    lld/trunk/test/elf2/Inputs/shared-ppc64.s
    lld/trunk/test/elf2/ppc64-toc-restore.s
Modified:
    lld/trunk/ELF/InputSection.cpp
    lld/trunk/ELF/InputSection.h
    lld/trunk/ELF/Target.cpp
    lld/trunk/ELF/Target.h

Modified: lld/trunk/ELF/InputSection.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.cpp?rev=250110&r1=250109&r2=250110&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.cpp (original)
+++ lld/trunk/ELF/InputSection.cpp Mon Oct 12 16:19:18 2015
@@ -28,7 +28,8 @@ InputSection<ELFT>::InputSection(ObjectF
 template <class ELFT>
 template <bool isRela>
 void InputSection<ELFT>::relocate(
-    uint8_t *Buf, iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
+    uint8_t *Buf, uint8_t *BufEnd,
+    iterator_range<const Elf_Rel_Impl<ELFT, isRela> *> Rels,
     const ObjectFile<ELFT> &File, uintX_t BaseAddr) {
   typedef Elf_Rel_Impl<ELFT, isRela> RelType;
   bool IsMips64EL = File.getObj().isMips64EL();
@@ -41,8 +42,8 @@ void InputSection<ELFT>::relocate(
     const Elf_Shdr *SymTab = File.getSymbolTable();
     if (SymIndex < SymTab->sh_info) {
       uintX_t SymVA = getLocalRelTarget(File, RI);
-      Target->relocateOne(Buf, reinterpret_cast<const void *>(&RI), Type,
-                          BaseAddr, SymVA);
+      Target->relocateOne(Buf, BufEnd, reinterpret_cast<const void *>(&RI),
+                          Type, BaseAddr, SymVA);
       continue;
     }
 
@@ -60,7 +61,7 @@ void InputSection<ELFT>::relocate(
     } else if (isa<SharedSymbol<ELFT>>(Body)) {
       continue;
     }
-    Target->relocateOne(Buf, reinterpret_cast<const void *>(&RI), Type,
+    Target->relocateOne(Buf, BufEnd, reinterpret_cast<const void *>(&RI), Type,
                         BaseAddr, SymVA);
   }
 }
@@ -79,9 +80,9 @@ template <class ELFT> void InputSection<
   // Iterate over all relocation sections that apply to this section.
   for (const Elf_Shdr *RelSec : RelocSections) {
     if (RelSec->sh_type == SHT_RELA)
-      relocate(Base, EObj.relas(RelSec), *File, BaseAddr);
+      relocate(Base, Base + Data.size(), EObj.relas(RelSec), *File, BaseAddr);
     else
-      relocate(Base, EObj.rels(RelSec), *File, BaseAddr);
+      relocate(Base, Base + Data.size(), EObj.rels(RelSec), *File, BaseAddr);
   }
 }
 

Modified: lld/trunk/ELF/InputSection.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputSection.h?rev=250110&r1=250109&r2=250110&view=diff
==============================================================================
--- lld/trunk/ELF/InputSection.h (original)
+++ lld/trunk/ELF/InputSection.h Mon Oct 12 16:19:18 2015
@@ -60,7 +60,7 @@ public:
 
 private:
   template <bool isRela>
-  void relocate(uint8_t *Buf,
+  void relocate(uint8_t *Buf, uint8_t *BufEnd,
                 llvm::iterator_range<
                     const llvm::object::Elf_Rel_Impl<ELFT, isRela> *> Rels,
                 const ObjectFile<ELFT> &File, uintX_t BaseAddr);

Modified: lld/trunk/ELF/Target.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.cpp?rev=250110&r1=250109&r2=250110&view=diff
==============================================================================
--- lld/trunk/ELF/Target.cpp (original)
+++ lld/trunk/ELF/Target.cpp Mon Oct 12 16:19:18 2015
@@ -64,8 +64,9 @@ bool X86TargetInfo::relocNeedsPlt(uint32
 static void add32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) + V); }
 static void or32le(uint8_t *L, int32_t V) { write32le(L, read32le(L) | V); }
 
-void X86TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                                uint64_t BaseAddr, uint64_t SymVA) const {
+void X86TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                                uint32_t Type, uint64_t BaseAddr,
+                                uint64_t SymVA) const {
   typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
   auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);
 
@@ -164,9 +165,9 @@ bool X86_64TargetInfo::isRelRelative(uin
   }
 }
 
-void X86_64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
-                                   uint32_t Type, uint64_t BaseAddr,
-                                   uint64_t SymVA) const {
+void X86_64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+                                   const void *RelP, uint32_t Type,
+                                   uint64_t BaseAddr, uint64_t SymVA) const {
   typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
   auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
 
@@ -306,7 +307,8 @@ bool PPC64TargetInfo::isRelRelative(uint
   }
 }
 
-void PPC64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
+void PPC64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+                                  const void *RelP, uint32_t Type,
                                   uint64_t BaseAddr, uint64_t SymVA) const {
   typedef ELFFile<ELF64BE>::Elf_Rela Elf_Rela;
   auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
@@ -397,6 +399,14 @@ void PPC64TargetInfo::relocateOne(uint8_
     if (!isInt<24>(R - P))
       error("Relocation R_PPC64_REL24 overflow");
     write32be(L, (read32be(L) & ~Mask) | ((R - P) & Mask));
+
+    uint64_t PltStart = Out<ELF64BE>::Plt->getVA();
+    uint64_t PltEnd = PltStart + Out<ELF64BE>::Plt->getSize();
+    bool InPlt = PltStart <= S + A && S + A < PltEnd;
+
+    if (InPlt && L + 8 < BufEnd &&
+        read32be(L + 4) == 0x60000000 /* nop */)
+      write32be(L + 4, 0xe8410028); // ld %r2, 40(%r1)
     break;
   }
   case R_PPC64_REL32:
@@ -429,7 +439,8 @@ bool PPCTargetInfo::relocNeedsGot(uint32
 bool PPCTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
   return false;
 }
-void PPCTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
+void PPCTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+                                const void *RelP, uint32_t Type,
                                 uint64_t BaseAddr, uint64_t SymVA) const {}
 
 ARMTargetInfo::ARMTargetInfo() {
@@ -445,7 +456,8 @@ bool ARMTargetInfo::relocNeedsGot(uint32
 bool ARMTargetInfo::relocNeedsPlt(uint32_t Type, const SymbolBody &S) const {
   return false;
 }
-void ARMTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
+void ARMTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+                                const void *RelP, uint32_t Type,
                                 uint64_t BaseAddr, uint64_t SymVA) const {}
 
 AArch64TargetInfo::AArch64TargetInfo() {
@@ -478,9 +490,9 @@ static uint64_t getAArch64Page(uint64_t
   return Expr & (~static_cast<uint64_t>(0xFFF));
 }
 
-void AArch64TargetInfo::relocateOne(uint8_t *Buf, const void *RelP,
-                                    uint32_t Type, uint64_t BaseAddr,
-                                    uint64_t SymVA) const {
+void AArch64TargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+                                    const void *RelP, uint32_t Type,
+                                    uint64_t BaseAddr, uint64_t SymVA) const {
   typedef ELFFile<ELF64LE>::Elf_Rela Elf_Rela;
   auto &Rel = *reinterpret_cast<const Elf_Rela *>(RelP);
 
@@ -544,7 +556,8 @@ bool MipsTargetInfo::relocNeedsPlt(uint3
   return false;
 }
 
-void MipsTargetInfo::relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
+void MipsTargetInfo::relocateOne(uint8_t *Buf, uint8_t *BufEnd,
+                                 const void *RelP, uint32_t Type,
                                  uint64_t BaseAddr, uint64_t SymVA) const {
   typedef ELFFile<ELF32LE>::Elf_Rel Elf_Rel;
   auto &Rel = *reinterpret_cast<const Elf_Rel *>(RelP);

Modified: lld/trunk/ELF/Target.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Target.h?rev=250110&r1=250109&r2=250110&view=diff
==============================================================================
--- lld/trunk/ELF/Target.h (original)
+++ lld/trunk/ELF/Target.h Mon Oct 12 16:19:18 2015
@@ -33,8 +33,9 @@ public:
   virtual bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const = 0;
   virtual bool relocPointsToGot(uint32_t Type) const;
   virtual bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const = 0;
-  virtual void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                           uint64_t BaseAddr, uint64_t SymVA) const = 0;
+  virtual void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                           uint32_t Type, uint64_t BaseAddr,
+                           uint64_t SymVA) const = 0;
 
   virtual ~TargetInfo();
 
@@ -56,8 +57,9 @@ public:
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocPointsToGot(uint32_t Type) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
-  void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                   uint64_t BaseAddr, uint64_t SymVA) const override;
+  void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                   uint32_t Type, uint64_t BaseAddr,
+                   uint64_t SymVA) const override;
 };
 
 class X86_64TargetInfo final : public TargetInfo {
@@ -67,8 +69,9 @@ public:
                      uint64_t PltEntryAddr) const override;
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
-  void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                   uint64_t BaseAddr, uint64_t SymVA) const override;
+  void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                   uint32_t Type, uint64_t BaseAddr,
+                   uint64_t SymVA) const override;
   bool isRelRelative(uint32_t Type) const override;
 };
 
@@ -79,8 +82,9 @@ public:
                      uint64_t PltEntryAddr) const override;
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
-  void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                   uint64_t BaseAddr, uint64_t SymVA) const override;
+  void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                   uint32_t Type, uint64_t BaseAddr,
+                   uint64_t SymVA) const override;
   bool isRelRelative(uint32_t Type) const override;
 };
 
@@ -91,8 +95,9 @@ public:
                      uint64_t PltEntryAddr) const override;
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
-  void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                   uint64_t BaseAddr, uint64_t SymVA) const override;
+  void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                   uint32_t Type, uint64_t BaseAddr,
+                   uint64_t SymVA) const override;
 };
 
 class ARMTargetInfo final : public TargetInfo {
@@ -102,8 +107,9 @@ public:
                      uint64_t PltEntryAddr) const override;
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
-  void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                   uint64_t BaseAddr, uint64_t SymVA) const override;
+  void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                   uint32_t Type, uint64_t BaseAddr,
+                   uint64_t SymVA) const override;
 };
 
 class AArch64TargetInfo final : public TargetInfo {
@@ -113,8 +119,9 @@ public:
                      uint64_t PltEntryAddr) const override;
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
-  void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                   uint64_t BaseAddr, uint64_t SymVA) const override;
+  void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                   uint32_t Type, uint64_t BaseAddr,
+                   uint64_t SymVA) const override;
 };
 
 class MipsTargetInfo final : public TargetInfo {
@@ -124,8 +131,9 @@ public:
                      uint64_t PltEntryAddr) const override;
   bool relocNeedsGot(uint32_t Type, const SymbolBody &S) const override;
   bool relocNeedsPlt(uint32_t Type, const SymbolBody &S) const override;
-  void relocateOne(uint8_t *Buf, const void *RelP, uint32_t Type,
-                   uint64_t BaseAddr, uint64_t SymVA) const override;
+  void relocateOne(uint8_t *Buf, uint8_t *BufEnd, const void *RelP,
+                   uint32_t Type, uint64_t BaseAddr,
+                   uint64_t SymVA) const override;
 };
 
 extern std::unique_ptr<TargetInfo> Target;

Added: lld/trunk/test/elf2/Inputs/shared-ppc64.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/Inputs/shared-ppc64.s?rev=250110&view=auto
==============================================================================
--- lld/trunk/test/elf2/Inputs/shared-ppc64.s (added)
+++ lld/trunk/test/elf2/Inputs/shared-ppc64.s Mon Oct 12 16:19:18 2015
@@ -0,0 +1,9 @@
+.section        ".opd","aw"
+.global bar
+bar:
+.quad   .Lbar,.TOC. at tocbase,0
+.quad   .Lbar,0,0
+
+.text
+.Lbar:
+        blr

Added: lld/trunk/test/elf2/ppc64-toc-restore.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/ppc64-toc-restore.s?rev=250110&view=auto
==============================================================================
--- lld/trunk/test/elf2/ppc64-toc-restore.s (added)
+++ lld/trunk/test/elf2/ppc64-toc-restore.s Mon Oct 12 16:19:18 2015
@@ -0,0 +1,45 @@
+// 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.lld2 -shared %t2.o -o %t2.so
+// RUN: ld.lld2 -dynamic-linker /lib64/ld64.so.1 -rpath foo -rpath bar --export-dynamic %t.o %t2.so -o %t
+// RUN: llvm-objdump -d %t | FileCheck %s
+// REQUIRES: ppc
+
+// CHECK: Disassembly of section .text:
+
+.global _start
+_start:
+  bl bar
+  nop
+
+// CHECK: _start:
+// CHECK: 10010000:       48 00 00 21     bl .+32
+// CHECK-NOT: 10010004:       60 00 00 00     nop
+// CHECK: 10010004:       e8 41 00 28     ld 2, 40(1)
+
+.global noret
+noret:
+  bl bar
+  li 5, 7
+
+// CHECK: noret:
+// CHECK: 10010008:       48 00 00 19     bl .+24
+// CHECK: 1001000c:       38 a0 00 07     li 5, 7
+
+.global noretend
+noretend:
+  bl bar
+
+// CHECK: noretend:
+// CHECK: 10010010:       48 00 00 11     bl .+16
+
+.global noretb
+noretb:
+  b bar
+
+// CHECK: noretb:
+// CHECK: 10010014:       48 00 00 0c     b .+12
+
+// CHECK: Disassembly of section .plt:
+// CHECK: .plt:
+// CHECK: 10010020:




More information about the llvm-commits mailing list