[lld] r247992 - Start adding support for creating the GOT.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 18 07:40:20 PDT 2015


Author: rafael
Date: Fri Sep 18 09:40:19 2015
New Revision: 247992

URL: http://llvm.org/viewvc/llvm-project?rev=247992&view=rev
Log:
Start adding support for creating the GOT.

With this a program can call into a shared library with

  jmp *foo at GOTPCREL(%rip)

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

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=247992&r1=247991&r2=247992&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Fri Sep 18 09:40:19 2015
@@ -134,7 +134,7 @@ public:
 
   ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
 
-  const SymbolBody *getSymbolBody(uint32_t SymbolIndex) const {
+  SymbolBody *getSymbolBody(uint32_t SymbolIndex) const {
     uint32_t FirstNonLocal = this->Symtab->sh_info;
     if (SymbolIndex < FirstNonLocal)
       return nullptr;

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=247992&r1=247991&r2=247992&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Fri Sep 18 09:40:19 2015
@@ -70,6 +70,10 @@ public:
   }
   void setDynamicSymbolTableIndex(unsigned V) { DynamicSymbolTableIndex = V; }
 
+  unsigned getGotIndex() const { return GotIndex; }
+  bool isInGot() const { return GotIndex != -1U; }
+  void setGotIndex(unsigned I) { GotIndex = 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
@@ -96,6 +100,7 @@ protected:
   unsigned MostConstrainingVisibility : 2;
   unsigned IsUsedInRegularObj : 1;
   unsigned DynamicSymbolTableIndex = 0;
+  unsigned GotIndex = -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=247992&r1=247991&r2=247992&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Fri Sep 18 09:40:19 2015
@@ -81,6 +81,8 @@ public:
   }
   uint32_t getType() { return Header.sh_type; }
 
+  static unsigned getAddrSize() { return Is64Bits ? 8 : 4; }
+
   virtual void finalize() {}
   virtual void writeTo(uint8_t *Buf) = 0;
 
@@ -98,17 +100,55 @@ template <class ELFT> struct DynamicRelo
   const Elf_Rel &RI;
 };
 
+static bool relocNeedsGOT(uint32_t Type) {
+  switch (Type) {
+  default:
+    return false;
+  case R_X86_64_GOTPCREL:
+    return true;
+  }
+}
+
+template <class ELFT>
+class GotSection final : public OutputSectionBase<ELFT::Is64Bits> {
+  typedef OutputSectionBase<ELFT::Is64Bits> Base;
+  typedef typename Base::uintX_t uintX_t;
+
+public:
+  GotSection()
+      : OutputSectionBase<ELFT::Is64Bits>(".got", SHT_PROGBITS,
+                                          SHF_ALLOC | SHF_WRITE) {
+    this->Header.sh_addralign = this->getAddrSize();
+  }
+  void finalize() override {
+    this->Header.sh_size = Entries.size() * this->getAddrSize();
+  }
+  void writeTo(uint8_t *Buf) override {}
+  void addEntry(SymbolBody *Sym) {
+    Sym->setGotIndex(Entries.size());
+    Entries.push_back(Sym);
+  }
+  bool empty() const { return Entries.empty(); }
+  uintX_t getEntryAddr(const SymbolBody &B) const {
+    return this->getVA() + B.getGotIndex() * this->getAddrSize();
+  }
+
+private:
+  std::vector<const SymbolBody *> Entries;
+};
+
 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;
 
 public:
-  RelocationSection(SymbolTableSection<ELFT> &DynSymSec, bool IsRela)
+  RelocationSection(SymbolTableSection<ELFT> &DynSymSec,
+                    const GotSection<ELFT> &GotSec, bool IsRela)
       : OutputSectionBase<ELFT::Is64Bits>(IsRela ? ".rela.dyn" : ".rel.dyn",
                                           IsRela ? SHT_RELA : SHT_REL,
                                           SHF_ALLOC),
-        DynSymSec(DynSymSec), IsRela(IsRela) {
+        DynSymSec(DynSymSec), GotSec(GotSec), IsRela(IsRela) {
     this->Header.sh_entsize = IsRela ? sizeof(Elf_Rela) : sizeof(Elf_Rel);
     this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
   }
@@ -127,12 +167,18 @@ public:
       OutputSection<ELFT> *Out = C.getOutputSection();
       uint32_t SymIndex = RI.getSymbol(IsMips64EL);
       const SymbolBody *Body = C.getFile()->getSymbolBody(SymIndex);
-
-      P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA();
-      P->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
-                          RI.getType(IsMips64EL), IsMips64EL);
-      if (IsRela)
-        P->r_addend = static_cast<const Elf_Rela &>(RI).r_addend;
+      uint32_t Type = RI.getType(IsMips64EL);
+      if (relocNeedsGOT(Type)) {
+        P->r_offset = GotSec.getEntryAddr(*Body);
+        P->setSymbolAndType(Body->getDynamicSymbolTableIndex(),
+                            R_X86_64_GLOB_DAT, IsMips64EL);
+      } else {
+        P->r_offset = RI.r_offset + C.getOutputSectionOff() + Out->getVA();
+        P->setSymbolAndType(Body->getDynamicSymbolTableIndex(), Type,
+                            IsMips64EL);
+        if (IsRela)
+          P->r_addend = static_cast<const Elf_Rela &>(RI).r_addend;
+      }
 
       ++P;
     }
@@ -143,6 +189,7 @@ public:
 private:
   std::vector<DynamicReloc<ELFT>> Relocs;
   SymbolTableSection<ELFT> &DynSymSec;
+  const GotSection<ELFT> &GotSec;
   const bool IsRela;
 };
 }
@@ -155,8 +202,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(StringRef Name, uint32_t sh_type, uintX_t sh_flags)
-      : OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags) {}
+  OutputSection(const GotSection<ELFT> &GotSec, StringRef Name,
+                uint32_t sh_type, uintX_t sh_flags)
+      : OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags),
+        GotSec(GotSec) {}
 
   void addChunk(SectionChunk<ELFT> *C);
   void writeTo(uint8_t *Buf) override;
@@ -173,6 +222,7 @@ public:
 
 private:
   std::vector<SectionChunk<ELFT> *> Chunks;
+  const GotSection<ELFT> &GotSec;
 };
 
 namespace {
@@ -507,7 +557,7 @@ public:
   typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
   Writer(SymbolTable *T)
       : SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec),
-        RelaDynSec(DynSymSec, T->shouldUseRela()), HashSec(DynSymSec),
+        RelaDynSec(DynSymSec, GotSec, T->shouldUseRela()), HashSec(DynSymSec),
         DynamicSec(*T, HashSec, RelaDynSec) {}
   void run();
 
@@ -559,6 +609,8 @@ private:
 
   RelocationSection<ELFT> RelaDynSec;
 
+  GotSection<ELFT> GotSec;
+
   HashTableSection<ELFT> HashSec;
 
   DynamicSection<ELFT> DynamicSec;
@@ -676,16 +728,22 @@ void OutputSection<ELFT>::relocate(
     if (!Body)
       continue;
 
+    uint32_t Type = RI.getType(IsMips64EL);
     uintX_t SymVA;
-    if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(Body))
+    if (auto *DR = dyn_cast<DefinedRegular<ELFT>>(Body)) {
       SymVA = getSymVA<ELFT>(DR);
-    else if (auto *DA = dyn_cast<DefinedAbsolute<ELFT>>(Body))
+    } else if (auto *DA = dyn_cast<DefinedAbsolute<ELFT>>(Body)) {
       SymVA = DA->Sym.st_value;
-    else
+    } else if (auto *S = dyn_cast<SharedSymbol<ELFT>>(Body)) {
+      if (!relocNeedsGOT(Type))
+        continue;
+      SymVA = GotSec.getEntryAddr(*S);
+      Type = R_X86_64_PC32;
+    } else {
       // Skip unsupported for now.
       continue;
+    }
 
-    uint32_t Type = RI.getType(IsMips64EL);
     relocateOne(Buf, RI, Type, BaseAddr, SymVA);
   }
 }
@@ -899,12 +957,17 @@ void Writer<ELFT>::scanRelocs(
   bool IsMips64EL = File.getObj()->isMips64EL();
   for (const RelType &RI : Rels) {
     uint32_t SymIndex = RI.getSymbol(IsMips64EL);
-    const SymbolBody *Body = File.getSymbolBody(SymIndex);
+    SymbolBody *Body = File.getSymbolBody(SymIndex);
     if (!Body)
       continue;
     auto *S = dyn_cast<SharedSymbol<ELFT>>(Body);
     if (!S)
       continue;
+    if (relocNeedsGOT(RI.getType(IsMips64EL))) {
+      if (Body->isInGot())
+        continue;
+      GotSec.addEntry(Body);
+    }
     RelaDynSec.addReloc({C, RI});
   }
 }
@@ -934,7 +997,7 @@ template <class ELFT> void Writer<ELFT>:
     OutputSection<ELFT> *&Sec = Map[Key];
     if (!Sec) {
       Sec = new (CAlloc.Allocate())
-          OutputSection<ELFT>(Key.Name, Key.sh_type, Key.sh_flags);
+          OutputSection<ELFT>(GotSec, Key.Name, Key.sh_type, Key.sh_flags);
       OutputSections.push_back(Sec);
     }
     return Sec;
@@ -1009,6 +1072,8 @@ template <class ELFT> void Writer<ELFT>:
     OutputSections.push_back(&DynStrSec);
     if (RelaDynSec.hasRelocs())
       OutputSections.push_back(&RelaDynSec);
+    if (!GotSec.empty())
+      OutputSections.push_back(&GotSec);
   }
 
   std::stable_sort(OutputSections.begin(), OutputSections.end(),

Added: lld/trunk/test/elf2/got.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/got.s?rev=247992&view=auto
==============================================================================
--- lld/trunk/test/elf2/got.s (added)
+++ lld/trunk/test/elf2/got.s Fri Sep 18 09:40:19 2015
@@ -0,0 +1,45 @@
+// 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: .got
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_WRITE
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x15000
+// CHECK-NEXT: Offset:
+// CHECK-NEXT: Size: 16
+// CHECK-NEXT: Link: 0
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+
+// 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:
+//  0x15000 - (0x11000 + 2) - 4 = 16378
+//  0x15000 - (0x11006 + 2) - 4 = 16372
+//  0x15008 - (0x1100c + 2) - 4 = 16374
+
+// DISASM:      _start:
+// DISASM-NEXT:   11000:  ff 25 fa 3f 00 00  jmpq  *16378(%rip)
+// DISASM-NEXT:   11006:  ff 25 f4 3f 00 00  jmpq  *16372(%rip)
+// DISASM-NEXT:   1100c:  ff 25 f6 3f 00 00  jmpq  *16374(%rip)
+
+.global _start
+_start:
+  jmp *bar at GOTPCREL(%rip)
+  jmp *bar at GOTPCREL(%rip)
+  jmp *zed at GOTPCREL(%rip)




More information about the llvm-commits mailing list