[lld] r248165 - Start adding support for PLT.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 08:11:30 PDT 2015


Author: rafael
Date: Mon Sep 21 10:11:29 2015
New Revision: 248165

URL: http://llvm.org/viewvc/llvm-project?rev=248165&view=rev
Log:
Start adding support for PLT.

For now this doesn't support lazy symbol resolution, but is enough to link
and run a program with

jmp foo at PLT

Added:
    lld/trunk/test/elf2/plt.s
Modified:
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=248165&r1=248164&r2=248165&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Mon Sep 21 10:11:29 2015
@@ -75,6 +75,10 @@ public:
   bool isInGot() const { return GotIndex != -1U; }
   void setGotIndex(unsigned I) { GotIndex = I; }
 
+  unsigned getPltIndex() const { return PltIndex; }
+  bool isInPlt() const { return PltIndex != -1U; }
+  void setPltIndex(unsigned I) { PltIndex = I; }
+
   // A SymbolBody has a backreference to a Symbol. Originally they are
   // doubly-linked. A backreference will never change. But the pointer
   // in the Symbol may be mutated by the resolver. If you have a
@@ -102,6 +106,7 @@ protected:
   unsigned IsUsedInRegularObj : 1;
   unsigned DynamicSymbolTableIndex = 0;
   unsigned GotIndex = -1;
+  unsigned PltIndex = -1;
   StringRef Name;
   Symbol *Backref = nullptr;
 };

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=248165&r1=248164&r2=248165&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Mon Sep 21 10:11:29 2015
@@ -100,7 +100,18 @@ template <class ELFT> struct DynamicRelo
   const Elf_Rel &RI;
 };
 
+static bool relocNeedsPLT(uint32_t Type) {
+  switch (Type) {
+  default:
+    return false;
+  case R_X86_64_PLT32:
+    return true;
+  }
+}
+
 static bool relocNeedsGOT(uint32_t Type) {
+  if (relocNeedsPLT(Type))
+    return true;
   switch (Type) {
   default:
     return false;
@@ -138,6 +149,58 @@ private:
 };
 
 template <class ELFT>
+class PltSection final : public OutputSectionBase<ELFT::Is64Bits> {
+  typedef OutputSectionBase<ELFT::Is64Bits> Base;
+  typedef typename Base::uintX_t uintX_t;
+
+public:
+  PltSection(const GotSection<ELFT> &GotSec)
+      : OutputSectionBase<ELFT::Is64Bits>(".plt", SHT_PROGBITS,
+                                          SHF_ALLOC | SHF_EXECINSTR),
+        GotSec(GotSec) {
+    this->Header.sh_addralign = 16;
+  }
+  void finalize() override {
+    this->Header.sh_size = Entries.size() * EntrySize;
+  }
+  void writeTo(uint8_t *Buf) override {
+    uintptr_t Start = reinterpret_cast<uintptr_t>(Buf);
+    ArrayRef<uint8_t> Jmp = {0xff, 0x25}; // jmpq *val(%rip)
+    for (const SymbolBody *E : Entries) {
+      uintptr_t InstPos = reinterpret_cast<uintptr_t>(Buf);
+
+      memcpy(Buf, Jmp.data(), Jmp.size());
+      Buf += Jmp.size();
+
+      uintptr_t OffsetInPLT = (InstPos + 6) - Start;
+      uintptr_t Delta = GotSec.getEntryAddr(*E) - (this->getVA() + OffsetInPLT);
+      assert(isInt<32>(Delta));
+      support::endian::write32le(Buf, Delta);
+      Buf += 4;
+
+      *Buf = 0x90; // nop
+      ++Buf;
+      *Buf = 0x90; // nop
+      ++Buf;
+    }
+  }
+  void addEntry(SymbolBody *Sym) {
+    Sym->setPltIndex(Entries.size());
+    Entries.push_back(Sym);
+  }
+  bool empty() const { return Entries.empty(); }
+  uintX_t getEntryAddr(const SymbolBody &B) const {
+    return this->getVA() + B.getPltIndex() * EntrySize;
+  }
+
+  static const unsigned EntrySize = 8;
+
+private:
+  std::vector<const SymbolBody *> Entries;
+  const GotSection<ELFT> &GotSec;
+};
+
+template <class ELFT>
 class RelocationSection final : public OutputSectionBase<ELFT::Is64Bits> {
   typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
   typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
@@ -202,10 +265,10 @@ public:
   typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
   typedef typename ELFFile<ELFT>::Elf_Rel Elf_Rel;
   typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
-  OutputSection(const GotSection<ELFT> &GotSec, StringRef Name,
-                uint32_t sh_type, uintX_t sh_flags)
+  OutputSection(const PltSection<ELFT> &PltSec, const GotSection<ELFT> &GotSec,
+                StringRef Name, uint32_t sh_type, uintX_t sh_flags)
       : OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags),
-        GotSec(GotSec) {}
+        PltSec(PltSec), GotSec(GotSec) {}
 
   void addChunk(SectionChunk<ELFT> *C);
   void writeTo(uint8_t *Buf) override;
@@ -222,6 +285,7 @@ public:
 
 private:
   std::vector<SectionChunk<ELFT> *> Chunks;
+  const PltSection<ELFT> &PltSec;
   const GotSection<ELFT> &GotSec;
 };
 
@@ -557,8 +621,8 @@ public:
   typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
   Writer(SymbolTable *T)
       : SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec),
-        RelaDynSec(DynSymSec, GotSec, T->shouldUseRela()), HashSec(DynSymSec),
-        DynamicSec(*T, HashSec, RelaDynSec) {}
+        RelaDynSec(DynSymSec, GotSec, T->shouldUseRela()), PltSec(GotSec),
+        HashSec(DynSymSec), DynamicSec(*T, HashSec, RelaDynSec) {}
   void run();
 
   const OutputSection<ELFT> &getBSS() const {
@@ -610,6 +674,7 @@ private:
   RelocationSection<ELFT> RelaDynSec;
 
   GotSection<ELFT> GotSec;
+  PltSection<ELFT> PltSec;
 
   HashTableSection<ELFT> HashSec;
 
@@ -744,10 +809,15 @@ void OutputSection<ELFT>::relocate(
       break;
     }
     case SymbolBody::SharedKind:
-      if (!relocNeedsGOT(Type))
+      if (relocNeedsPLT(Type)) {
+        SymVA = PltSec.getEntryAddr(*Body);
+        Type = R_X86_64_PC32;
+      } else if (relocNeedsGOT(Type)) {
+        SymVA = GotSec.getEntryAddr(*Body);
+        Type = R_X86_64_PC32;
+      } else {
         continue;
-      SymVA = GotSec.getEntryAddr(*Body);
-      Type = R_X86_64_PC32;
+      }
       break;
     case SymbolBody::UndefinedKind:
       assert(Body->isWeak() && "Undefined symbol reached writer");
@@ -978,7 +1048,13 @@ void Writer<ELFT>::scanRelocs(
     auto *S = dyn_cast<SharedSymbol<ELFT>>(Body);
     if (!S)
       continue;
-    if (relocNeedsGOT(RI.getType(IsMips64EL))) {
+    uint32_t Type = RI.getType(IsMips64EL);
+    if (relocNeedsPLT(Type)) {
+      if (Body->isInPlt())
+        continue;
+      PltSec.addEntry(Body);
+    }
+    if (relocNeedsGOT(Type)) {
       if (Body->isInGot())
         continue;
       GotSec.addEntry(Body);
@@ -1011,8 +1087,8 @@ template <class ELFT> void Writer<ELFT>:
     SectionKey<ELFT::Is64Bits> Key{Name, sh_type, sh_flags};
     OutputSection<ELFT> *&Sec = Map[Key];
     if (!Sec) {
-      Sec = new (CAlloc.Allocate())
-          OutputSection<ELFT>(GotSec, Key.Name, Key.sh_type, Key.sh_flags);
+      Sec = new (CAlloc.Allocate()) OutputSection<ELFT>(
+          PltSec, GotSec, Key.Name, Key.sh_type, Key.sh_flags);
       OutputSections.push_back(Sec);
     }
     return Sec;
@@ -1090,6 +1166,8 @@ template <class ELFT> void Writer<ELFT>:
       OutputSections.push_back(&RelaDynSec);
     if (!GotSec.empty())
       OutputSections.push_back(&GotSec);
+    if (!PltSec.empty())
+      OutputSections.push_back(&PltSec);
   }
 
   std::stable_sort(OutputSections.begin(), OutputSections.end(),

Added: lld/trunk/test/elf2/plt.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/plt.s?rev=248165&view=auto
==============================================================================
--- lld/trunk/test/elf2/plt.s (added)
+++ lld/trunk/test/elf2/plt.s Mon Sep 21 10:11:29 2015
@@ -0,0 +1,57 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t.o
+// RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %p/Inputs/shared.s -o %t2.o
+// RUN: lld -flavor gnu2 -shared %t2.o -o %t2.so
+// RUN: lld -flavor gnu2 %t.o %t2.so -o %t
+// RUN: llvm-readobj -s -r %t | FileCheck %s
+// RUN: llvm-objdump -d %t | FileCheck --check-prefix=DISASM %s
+// REQUIRES: x86
+
+// CHECK:      Name: .plt
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x16000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 16
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     0x15000 R_X86_64_GLOB_DAT bar 0x0
+// CHECK-NEXT:     0x15008 R_X86_64_GLOB_DAT zed 0x0
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+// Unfortunately FileCheck can't do math, so we have to check for explicit
+// values:
+
+// 0x16000 - (0x11000 + 1) - 4 = 20475
+// 0x16000 - (0x11005 + 1) - 4 = 20470
+// 0x16008 - (0x1100a + 1) - 4 = 20473
+
+// DISASM:      _start:
+// DISASM-NEXT:   11000:  e9 fb 4f 00 00  jmp  20475
+// DISASM-NEXT:   11005:  e9 f6 4f 00 00  jmp  20470
+// DISASM-NEXT:   1100a:  e9 f9 4f 00 00  jmp  20473
+
+// 0x15000 - 0x16006  = -4102
+// 0x15008 - 0x1600e  = -4102
+
+// DISASM:      Disassembly of section .plt:
+// DISASM-NEXT: .plt:
+// DISASM-NEXT:   16000:  ff 25 fa ef ff ff  jmpq *-4102(%rip)
+// DISASM-NEXT:   16006:  90                 nop
+// DISASM-NEXT:   16007:  90                 nop
+// DISASM-NEXT:   16008:  ff 25 fa ef ff ff  jmpq *-4102(%rip)
+// DISASM-NEXT:   1600e:  90                 nop
+// DISASM-NEXT:   1600f:  90                 nop
+
+.global _start
+_start:
+  jmp bar at PLT
+  jmp bar at PLT
+  jmp zed at PLT




More information about the llvm-commits mailing list