[lld] r247811 - Start creating dynamic relocations.

Rafael Espindola via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 16 08:54:15 PDT 2015


Author: rafael
Date: Wed Sep 16 10:54:15 2015
New Revision: 247811

URL: http://llvm.org/viewvc/llvm-project?rev=247811&view=rev
Log:
Start creating dynamic relocations.

For now we don't create got/plt and only Elf_Rela is supported.

Added:
    lld/trunk/test/elf2/dynamic-reloc.s
Modified:
    lld/trunk/ELF/Chunks.h
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Chunks.h?rev=247811&r1=247810&r2=247811&view=diff
==============================================================================
--- lld/trunk/ELF/Chunks.h (original)
+++ lld/trunk/ELF/Chunks.h Wed Sep 16 10:54:15 2015
@@ -38,7 +38,7 @@ public:
 
   StringRef getSectionName() const;
   const Elf_Shdr *getSectionHdr() const { return Header; }
-  ObjectFile<ELFT> *getFile() { return File; }
+  const ObjectFile<ELFT> *getFile() const { return File; }
 
   // The writer sets and uses the addresses.
   uintX_t getOutputSectionOff() const { return OutputSectionOff; }

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=247811&r1=247810&r2=247811&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Wed Sep 16 10:54:15 2015
@@ -131,7 +131,7 @@ public:
 
   ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
 
-  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=247811&r1=247810&r2=247811&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Wed Sep 16 10:54:15 2015
@@ -65,6 +65,11 @@ public:
     return MostConstrainingVisibility;
   }
 
+  unsigned getDynamicSymbolTableIndex() const {
+    return DynamicSymbolTableIndex;
+  }
+  void setDynamicSymbolTableIndex(unsigned V) { DynamicSymbolTableIndex = V; }
+
   // 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
@@ -90,6 +95,7 @@ protected:
   const unsigned IsWeak : 1;
   unsigned MostConstrainingVisibility : 2;
   unsigned IsUsedInRegularObj : 1;
+  unsigned DynamicSymbolTableIndex = 0;
   StringRef Name;
   Symbol *Backref = nullptr;
 };

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=247811&r1=247810&r2=247811&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Wed Sep 16 10:54:15 2015
@@ -90,6 +90,55 @@ protected:
   unsigned SectionIndex;
   ~OutputSectionBase() = default;
 };
+template <class ELFT> class SymbolTableSection;
+
+template <class ELFT> struct DynamicReloc {
+  typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
+  const SectionChunk<ELFT> &C;
+  const Elf_Rela &RI;
+};
+
+template <class ELFT>
+class RelocationSection final : public OutputSectionBase<ELFT::Is64Bits> {
+  typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
+
+public:
+  RelocationSection(SymbolTableSection<ELFT> &DynSymSec)
+      : OutputSectionBase<ELFT::Is64Bits>(".rela.dyn", SHT_RELA, SHF_ALLOC),
+        DynSymSec(DynSymSec) {
+    this->Header.sh_entsize = sizeof(Elf_Rela);
+    this->Header.sh_addralign = ELFT::Is64Bits ? 8 : 4;
+  }
+
+  void addReloc(const DynamicReloc<ELFT> &Reloc) { Relocs.push_back(Reloc); }
+  void finalize() override {
+    this->Header.sh_link = DynSymSec.getSectionIndex();
+    this->Header.sh_size = Relocs.size() * sizeof(Elf_Rela);
+  }
+  void writeTo(uint8_t *Buf) override {
+    auto *P = reinterpret_cast<Elf_Rela *>(Buf);
+    bool IsMips64EL = Relocs[0].C.getFile()->getObj()->isMips64EL();
+    for (const DynamicReloc<ELFT> &Rel : Relocs) {
+      const SectionChunk<ELFT> &C = Rel.C;
+      const Elf_Rela &RI = Rel.RI;
+      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);
+      P->r_addend = RI.r_addend;
+
+      ++P;
+    }
+  }
+  bool hasReocs() const { return !Relocs.empty(); }
+
+private:
+  std::vector<DynamicReloc<ELFT>> Relocs;
+  SymbolTableSection<ELFT> &DynSymSec;
+};
 }
 
 template <class ELFT>
@@ -99,14 +148,17 @@ public:
   typedef typename OutputSectionBase<ELFT::Is64Bits>::uintX_t uintX_t;
   typedef typename ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
   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(StringRef Name, uint32_t sh_type, uintX_t sh_flags,
+                RelocationSection<ELFT> &RelaDynSec)
+      : OutputSectionBase<ELFT::Is64Bits>(Name, sh_type, sh_flags),
+        RelaDynSec(RelaDynSec) {}
 
   void addChunk(SectionChunk<ELFT> *C);
   void writeTo(uint8_t *Buf) override;
 
 private:
   std::vector<SectionChunk<ELFT> *> Chunks;
+  RelocationSection<ELFT> &RelaDynSec;
 };
 
 namespace {
@@ -212,9 +264,11 @@ public:
     this->Header.sh_addralign = sizeof(Elf_Word);
   }
 
-  void addSymbol(StringRef Name) {
+  void addSymbol(SymbolBody *S) {
+    StringRef Name = S->getName();
     DynSymSec.addSymbol(Name);
     Hashes.push_back(hash(Name));
+    S->setDynamicSymbolTableIndex(Hashes.size());
   }
 
   void finalize() override {
@@ -363,9 +417,10 @@ public:
   typedef typename ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
   typedef typename ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
   typedef typename ELFFile<ELFT>::Elf_Sym Elf_Sym;
+  typedef typename ELFFile<ELFT>::Elf_Rela Elf_Rela;
   Writer(SymbolTable *T)
       : SymTabSec(*this, *T, StrTabSec), DynSymSec(*this, *T, DynStrSec),
-        HashSec(DynSymSec), DynamicSec(*T, HashSec) {}
+        RelaDynSec(DynSymSec), HashSec(DynSymSec), DynamicSec(*T, HashSec) {}
   void run();
 
   const OutputSection<ELFT> &getBSS() const {
@@ -375,6 +430,7 @@ public:
 
 private:
   void createSections();
+  void scanRelocs(const SectionChunk<ELFT> &C);
   void assignAddresses();
   void openFile(StringRef OutputPath);
   void writeHeader();
@@ -404,6 +460,8 @@ private:
   SymbolTableSection<ELFT> SymTabSec;
   SymbolTableSection<ELFT> DynSymSec;
 
+  RelocationSection<ELFT> RelaDynSec;
+
   HashTableSection<ELFT> HashSec;
 
   DynamicSection<ELFT> DynamicSec;
@@ -454,7 +512,8 @@ void OutputSection<ELFT>::addChunk(Secti
 }
 
 template <class ELFT>
-static typename ELFFile<ELFT>::uintX_t getSymVA(DefinedRegular<ELFT> *DR) {
+static typename ELFFile<ELFT>::uintX_t
+getSymVA(const DefinedRegular<ELFT> *DR) {
   const SectionChunk<ELFT> *SC = &DR->Section;
   OutputSection<ELFT> *OS = SC->getOutputSection();
   return OS->getVA() + SC->getOutputSectionOff() + DR->Sym.st_value;
@@ -463,7 +522,7 @@ static typename ELFFile<ELFT>::uintX_t g
 template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
   for (SectionChunk<ELFT> *C : Chunks) {
     C->writeTo(Buf);
-    ObjectFile<ELFT> *File = C->getFile();
+    const ObjectFile<ELFT> *File = C->getFile();
     ELFFile<ELFT> *EObj = File->getObj();
     uint8_t *Base = Buf + C->getOutputSectionOff();
 
@@ -474,7 +533,7 @@ template <class ELFT> void OutputSection
         continue;
       for (const Elf_Rela &RI : EObj->relas(RelSec)) {
         uint32_t SymIndex = RI.getSymbol(EObj->isMips64EL());
-        SymbolBody *Body = File->getSymbolBody(SymIndex);
+        const SymbolBody *Body = File->getSymbolBody(SymIndex);
         if (!Body)
           continue;
 
@@ -671,6 +730,38 @@ static bool compSec(OutputSectionBase<Is
   return (A->getFlags() & SHF_ALLOC) && !(B->getFlags() & SHF_ALLOC);
 }
 
+// The reason we have to do this early scan is as follows
+// * To mmap the output file, we need to know the size
+// * For that, we need to know how many dynamic relocs we will have.
+// It might be possible to avoid this by outputting the file with write:
+// * Write the allocated output sections, computing addresses.
+// * Apply relocations, recording which ones require a dynamic reloc.
+// * Write the dynamic relocations.
+// * Write the rest of the file.
+template <class ELFT>
+void Writer<ELFT>::scanRelocs(const SectionChunk<ELFT> &C) {
+  const ObjectFile<ELFT> *File = C.getFile();
+  ELFFile<ELFT> *EObj = File->getObj();
+
+  if (!(C.getSectionHdr()->sh_flags & SHF_ALLOC))
+    return;
+
+  for (const Elf_Shdr *RelSec : C.RelocSections) {
+    if (RelSec->sh_type != SHT_RELA)
+      continue;
+    for (const Elf_Rela &RI : EObj->relas(RelSec)) {
+      uint32_t SymIndex = RI.getSymbol(EObj->isMips64EL());
+      const SymbolBody *Body = File->getSymbolBody(SymIndex);
+      if (!Body)
+        continue;
+      auto *S = dyn_cast<SharedSymbol<ELFT>>(Body);
+      if (!S)
+        continue;
+      RelaDynSec.addReloc({C, RI});
+    }
+  }
+}
+
 // Create output section objects and add them to OutputSections.
 template <class ELFT> void Writer<ELFT>::createSections() {
   SmallDenseMap<SectionKey<ELFT::Is64Bits>, OutputSection<ELFT> *> Map;
@@ -680,27 +771,14 @@ 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>(Key.Name, Key.sh_type, Key.sh_flags, RelaDynSec);
       OutputSections.push_back(Sec);
     }
     return Sec;
   };
 
-  const SymbolTable &Symtab = SymTabSec.getSymTable();
-  for (const std::unique_ptr<ObjectFileBase> &FileB : Symtab.getObjectFiles()) {
-    auto &File = cast<ObjectFile<ELFT>>(*FileB);
-    for (SectionChunk<ELFT> *C : File.getChunks()) {
-      if (!C)
-        continue;
-      const Elf_Shdr *H = C->getSectionHdr();
-      OutputSection<ELFT> *Sec =
-          getSection(C->getSectionName(), H->sh_type, H->sh_flags);
-      Sec->addChunk(C);
-    }
-  }
-
-  BSSSec = getSection(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
   // FIXME: Try to avoid the extra walk over all global symbols.
+  const SymbolTable &Symtab = SymTabSec.getSymTable();
   std::vector<DefinedCommon<ELFT> *> CommonSymbols;
   for (auto &P : Symtab.getSymbols()) {
     StringRef Name = P.first;
@@ -718,9 +796,23 @@ template <class ELFT> void Writer<ELFT>:
     // need to add the symbols use by dynamic relocations when producing
     // an executable (ignoring --export-dynamic).
     if (needsDynamicSections())
-      HashSec.addSymbol(Name);
+      HashSec.addSymbol(Body);
+  }
+
+  for (const std::unique_ptr<ObjectFileBase> &FileB : Symtab.getObjectFiles()) {
+    auto &File = cast<ObjectFile<ELFT>>(*FileB);
+    for (SectionChunk<ELFT> *C : File.getChunks()) {
+      if (!C)
+        continue;
+      const Elf_Shdr *H = C->getSectionHdr();
+      OutputSection<ELFT> *Sec =
+          getSection(C->getSectionName(), H->sh_type, H->sh_flags);
+      Sec->addChunk(C);
+      scanRelocs(*C);
+    }
   }
 
+  BSSSec = getSection(".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
   // Sort the common symbols by alignment as an heuristic to pack them better.
   std::stable_sort(CommonSymbols.begin(), CommonSymbols.end(), cmpAlign<ELFT>);
   uintX_t Off = BSSSec->getSize();
@@ -744,6 +836,8 @@ template <class ELFT> void Writer<ELFT>:
     OutputSections.push_back(&HashSec);
     OutputSections.push_back(&DynamicSec);
     OutputSections.push_back(&DynStrSec);
+    if (RelaDynSec.hasReocs())
+      OutputSections.push_back(&RelaDynSec);
   }
 
   std::stable_sort(OutputSections.begin(), OutputSections.end(),

Added: lld/trunk/test/elf2/dynamic-reloc.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/dynamic-reloc.s?rev=247811&view=auto
==============================================================================
--- lld/trunk/test/elf2/dynamic-reloc.s (added)
+++ lld/trunk/test/elf2/dynamic-reloc.s Wed Sep 16 10:54:15 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 -r --expand-relocs -s %t | FileCheck %s
+// REQUIRES: x86
+
+// CHECK:      Name: .text
+// CHECK-NEXT: Type: SHT_PROGBITS
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT:   SHF_EXECINSTR
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: [[ADDR:.*]]
+
+// CHECK:      Index: 4
+// CHECK-NEXT: Name: .dynsym
+
+// CHECK:      Name: .rela.dyn
+// CHECK-NEXT: Type: SHT_RELA
+// CHECK-NEXT: Flags [
+// CHECK-NEXT:   SHF_ALLOC
+// CHECK-NEXT: ]
+// CHECK-NEXT: Address: 0x16000
+// CHECK-NEXT: Offset: 0x6000
+// CHECK-NEXT: Size: 24
+// CHECK-NEXT: Link: 4
+// CHECK-NEXT: Info: 0
+// CHECK-NEXT: AddressAlignment: 8
+// CHECK-NEXT: EntrySize: 24
+
+// CHECK:      Relocations [
+// CHECK-NEXT:   Section ({{.*}}) .rela.dyn {
+// CHECK-NEXT:     Relocation {
+// CHECK-NEXT:       Offset: [[ADDR]]
+// CHECK-NEXT:       Type: R_X86_64_64
+// CHECK-NEXT:       Symbol: bar
+// CHECK-NEXT:       Addend: 0x42
+// CHECK-NEXT:     }
+// CHECK-NEXT:   }
+// CHECK-NEXT: ]
+
+.global _start
+_start:
+.quad bar + 0x42




More information about the llvm-commits mailing list