[PATCH] D11612: [lld][ELF2] Apply relocations.

Rafael Espíndola via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 26 14:38:30 PDT 2015


Rebased to trunk with all tests passing.

Main issues I see so far:

* There seems to be more code than needed for the test.
* Treating local symbols like regular symbols is incredibly wasteful.
They don't need the replacement logic.

I will try to further reduce the patch tomorrow.


On 26 August 2015 at 16:49, Rafael Espíndola <rafael.espindola at gmail.com> wrote:
> Hacked to pass all tests.
>
> Trying to merge now.
>
> On 26 August 2015 at 16:35, Rafael Espíndola <rafael.espindola at gmail.com> wrote:
>> elf2/basic64be.s is still failing, looking.
>>
>> On 26 August 2015 at 16:26, Rafael Espíndola <rafael.espindola at gmail.com> wrote:
>>> The attached patch fixes the build and runs git-clang-format.
>>>
>>> On 26 August 2015 at 16:23, Rafael Espíndola <rafael.espindola at gmail.com> wrote:
>>>> This doesn't even compile:
>>>>
>>>> /home/espindola/llvm/llvm/tools/lld/ELF/Symbols.h:135:12: error: use
>>>> of undeclared identifier 'Sym'
>>>>     return Sym.st_value;
>>>>
>>>> On 26 August 2015 at 02:09, Rui Ueyama <ruiu at google.com> wrote:
>>>>> ruiu added a comment.
>>>>>
>>>>> Rafael should be the person who signs off.
>>>>>
>>>>>
>>>>> http://reviews.llvm.org/D11612
>>>>>
>>>>>
>>>>>
-------------- next part --------------
diff --git a/ELF/Chunks.cpp b/ELF/Chunks.cpp
index 11186b4..331e86b 100644
--- a/ELF/Chunks.cpp
+++ b/ELF/Chunks.cpp
@@ -9,6 +9,7 @@
 
 #include "Chunks.h"
 #include "Error.h"
+#include "InputFiles.h"
 
 using namespace llvm;
 using namespace llvm::ELF;
@@ -17,22 +18,21 @@ using namespace lld;
 using namespace lld::elf2;
 
 template <class ELFT>
-SectionChunk<ELFT>::SectionChunk(object::ELFFile<ELFT> *Obj,
-                                 const Elf_Shdr *Header)
-    : Obj(Obj), Header(Header) {}
+SectionChunk<ELFT>::SectionChunk(ObjectFile<ELFT> *F, const Elf_Shdr *Header)
+    : File(F), Header(Header) {}
 
 template <class ELFT> void SectionChunk<ELFT>::writeTo(uint8_t *Buf) {
   if (Header->sh_type == SHT_NOBITS)
     return;
   // Copy section contents from source object file to output file.
-  ArrayRef<uint8_t> Data = *Obj->getSectionContents(Header);
+  ArrayRef<uint8_t> Data = *File->getObj()->getSectionContents(Header);
   memcpy(Buf + OutputSectionOff, Data.data(), Data.size());
 
   // FIXME: Relocations
 }
 
 template <class ELFT> StringRef SectionChunk<ELFT>::getSectionName() const {
-  ErrorOr<StringRef> Name = Obj->getSectionName(Header);
+  ErrorOr<StringRef> Name = File->getObj()->getSectionName(Header);
   error(Name);
   return *Name;
 }
diff --git a/ELF/Chunks.h b/ELF/Chunks.h
index 4710182..41176d1 100644
--- a/ELF/Chunks.h
+++ b/ELF/Chunks.h
@@ -27,7 +27,7 @@ template <class ELFT> class SectionChunk {
   typedef typename llvm::object::ELFFile<ELFT>::uintX_t uintX_t;
 
 public:
-  SectionChunk(llvm::object::ELFFile<ELFT> *Obj, const Elf_Shdr *Header);
+  SectionChunk(ObjectFile<ELFT> *F, const Elf_Shdr *Header);
 
   // Returns the size of this chunk (even if this is a common or BSS.)
   size_t getSize() const { return Header->sh_size; }
@@ -38,6 +38,7 @@ public:
 
   StringRef getSectionName() const;
   const Elf_Shdr *getSectionHdr() const { return Header; }
+  ObjectFile<ELFT> *getFile() { return File; }
 
   // The writer sets and uses the addresses.
   uintX_t getOutputSectionOff() const { return OutputSectionOff; }
@@ -52,8 +53,8 @@ private:
   // to. The writer sets a value.
   uint64_t OutputSectionOff = 0;
 
-  // A file this chunk was created from.
-  llvm::object::ELFFile<ELFT> *Obj;
+  // The file this chunk was created from.
+  ObjectFile<ELFT> *File;
 
   OutputSection<ELFT> *Out = nullptr;
 
diff --git a/ELF/InputFiles.cpp b/ELF/InputFiles.cpp
index 14566dc..213ffd8 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -54,15 +54,22 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
     }
     case SHT_STRTAB:
     case SHT_NULL:
+      break;
     case SHT_RELA:
-    case SHT_REL:
+    case SHT_REL: {
+      auto RelocatedSec = ELFObj->getSection(Sec.sh_info);
+      if (!RelocatedSec)
+        error(RelocatedSec);
+      RelocMap.emplace_back(*RelocatedSec, &Sec);
       break;
+    }
     default:
-      Chunks[I] = new (Alloc) SectionChunk<ELFT>(this->getObj(), &Sec);
+      Chunks[I] = new (Alloc) SectionChunk<ELFT>(this, &Sec);
       break;
     }
     ++I;
   }
+  std::sort(RelocMap.begin(), RelocMap.end());
 }
 
 template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
@@ -76,10 +83,19 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::initializeSymbols() {
   uint32_t FirstNonLocal = Symtab->sh_info;
   if (FirstNonLocal > NumSymbols)
     error("Invalid sh_info in symbol table");
+  Elf_Sym_Range LocalSyms =
+      llvm::make_range(Syms.begin() + 1, Syms.begin() + FirstNonLocal);
   Syms = llvm::make_range(Syms.begin() + FirstNonLocal, Syms.end());
   SymbolBodies.reserve(NumSymbols);
-  for (const Elf_Sym &Sym : Syms)
-    SymbolBodies.push_back(createSymbolBody(StringTable, &Sym));
+  IndexedSymbolBodies.reserve(NumSymbols);
+  IndexedSymbolBodies.push_back(nullptr); // Skip the null entry.
+  for (const Elf_Sym &Sym : LocalSyms)
+    IndexedSymbolBodies.push_back(createSymbolBody(StringTable, &Sym));
+  for (const Elf_Sym &Sym : Syms) {
+    SymbolBody *S = createSymbolBody(StringTable, &Sym);
+    SymbolBodies.push_back(S);
+    IndexedSymbolBodies.push_back(S);
+  }
 }
 
 template <class ELFT>
@@ -100,6 +116,8 @@ SymbolBody *elf2::ObjectFile<ELFT>::createSymbolBody(StringRef StringTable,
   switch (Sym->getBinding()) {
   default:
     error("unexpected binding");
+  case STB_LOCAL:
+    return new (Alloc) DefinedRegular<ELFT>(Name, *Sym, *Chunks[SecIndex]);
   case STB_GLOBAL:
     if (Sym->isUndefined())
       return new (Alloc) Undefined<ELFT>(Name, *Sym);
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 774166c..24b5a4e 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -11,6 +11,9 @@
 #define LLD_ELF_INPUT_FILES_H
 
 #include "Chunks.h"
+#include "Error.h"
+#include "Symbols.h"
+
 #include "lld/Core/LLVM.h"
 #include "llvm/Object/ELF.h"
 
@@ -68,6 +71,21 @@ template <class ELFT> class ObjectFile : public ObjectFileBase {
   typedef typename llvm::object::ELFFile<ELFT>::Elf_Word Elf_Word;
 
 public:
+  struct RelocMapInfo {
+    RelocMapInfo(const Elf_Shdr *S, const Elf_Shdr *RS)
+        : Section(S), RelocSection(RS) {}
+
+    const Elf_Shdr *Section;
+    const Elf_Shdr *RelocSection;
+
+    bool operator<(const RelocMapInfo &Other) const {
+      // Pointer comparison is stable here as all pointers in a given RelocMap
+      // point to a single memory mapped file.
+      return std::tie(Section, RelocSection) <
+             std::tie(Other.Section, Other.RelocSection);
+    }
+  };
+
   bool isCompatibleWith(const ObjectFileBase &Other) const override;
 
   static Kind getKind() {
@@ -85,12 +103,24 @@ public:
 
   explicit ObjectFile(MemoryBufferRef M) : ObjectFileBase(getKind(), M) {}
   void parse() override;
+  const std::vector<RelocMapInfo> &getRelocations() const { return RelocMap; }
+
+  SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
+    if (SymbolIndex >= IndexedSymbolBodies.size())
+      error("Invalid symbol table index.");
+    SymbolBody *S = IndexedSymbolBodies[SymbolIndex];
+    if (S)
+      return S->getReplacement();
+    return nullptr;
+  }
 
   // Returns the underying ELF file.
   llvm::object::ELFFile<ELFT> *getObj() const { return ELFObj.get(); }
 
   ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
 
+  const Elf_Shdr *getSymtab() const { return Symtab; }
+
 private:
   void initializeChunks();
   void initializeSymbols();
@@ -103,6 +133,15 @@ private:
   std::vector<SectionChunk<ELFT> *> Chunks;
 
   const Elf_Shdr *Symtab = nullptr;
+
+  // Symbol bodies indexed the same as the symbol table.
+  std::vector<SymbolBody *> IndexedSymbolBodies;
+
+  // This vector contains a sorted list of <section, relocation section that
+  // applies to section> pairs. This is used to quickly find and iterate over
+  // the relocations for a given section.
+  std::vector<RelocMapInfo> RelocMap;
+
   ArrayRef<Elf_Word> SymtabSHNDX;
 };
 
diff --git a/ELF/Symbols.cpp b/ELF/Symbols.cpp
index 095940c..bb89a3f 100644
--- a/ELF/Symbols.cpp
+++ b/ELF/Symbols.cpp
@@ -43,3 +43,12 @@ int SymbolBody::compare(SymbolBody *Other) {
   }
   llvm_unreachable("unknown symbol kind");
 }
+
+namespace lld {
+namespace elf2 {
+template class DefinedRegular<llvm::object::ELF32LE>;
+template class DefinedRegular<llvm::object::ELF32BE>;
+template class DefinedRegular<llvm::object::ELF64LE>;
+template class DefinedRegular<llvm::object::ELF64BE>;
+}
+}
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 296fd40..ad1b59f 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -62,6 +62,7 @@ public:
   // has chosen the object among other objects having the same name,
   // you can access P->Backref->Body to get the resolver's result.
   void setBackref(Symbol *P) { Backref = P; }
+  SymbolBody *getReplacement() { return Backref ? Backref->Body : this; }
 
   // Decides which symbol should "win" in the symbol table, this or
   // the Other. Returns 1 if this wins, -1 if the Other wins, or 0 if
@@ -133,6 +134,10 @@ public:
   static bool classof(const SymbolBody *S) {
     return S->kind() == Base::DefinedRegularKind;
   }
+
+  typename llvm::object::ELFFile<ELFT>::uintX_t getValue() const {
+    return this->Sym.st_value;
+  }
 };
 
 template <class ELFT> class DefinedWeak : public Defined<ELFT> {
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 430b9c1..32cfb2c 100644
--- a/ELF/Writer.cpp
+++ b/ELF/Writer.cpp
@@ -10,12 +10,14 @@
 #include "Chunks.h"
 #include "Config.h"
 #include "Error.h"
+#include "Symbols.h"
 #include "SymbolTable.h"
 #include "Writer.h"
 #include "Symbols.h"
 
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/raw_ostream.h"
 
 using namespace llvm;
 using namespace llvm::ELF;
@@ -215,9 +217,57 @@ void OutputSection<ELFT>::addChunk(SectionChunk<ELFT> *C) {
   this->Header.sh_size = Off;
 }
 
+template <class ELFT>
+typename llvm::object::ELFFile<ELFT>::uintX_t
+getSymVA(DefinedRegular<ELFT> *DR) {
+  const SectionChunk<ELFT> *SC = &DR->Section;
+  OutputSection<ELFT> *OS = SC->getOutputSection();
+  return OS->getVA() + SC->getOutputSectionOff() + DR->getValue();
+}
+
 template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
-  for (SectionChunk<ELFT> *C : Chunks)
+  for (SectionChunk<ELFT> *C : Chunks) {
     C->writeTo(Buf);
+    const std::vector<typename ObjectFile<ELFT>::RelocMapInfo> &Relocs =
+        C->getFile()->getRelocations();
+    auto Hdr = C->getSectionHdr();
+    auto EObj = C->getFile()->getObj();
+    uint8_t *Base = Buf + C->getOutputSectionOff();
+    // Iterate over all relocation sections that apply to this section.
+    for (auto I = std::lower_bound(
+             Relocs.begin(), Relocs.end(),
+             typename ObjectFile<ELFT>::RelocMapInfo(Hdr, nullptr)),
+              E = Relocs.end();
+         I != E && I->Section == Hdr; ++I) {
+      // Only support RELA for now.
+      if (I->RelocSection->sh_type != SHT_RELA)
+        continue;
+      for (auto &RI : EObj->relas(I->RelocSection)) {
+        SymbolBody *Body =
+            C->getFile()->getSymbolBody(RI.getSymbol(EObj->isMips64EL()));
+        if (!Body)
+          continue;
+        // Skip undefined weak for now.
+        if (isa<UndefinedWeak<ELFT>>(Body))
+          continue;
+        if (!isa<DefinedRegular<ELFT>>(Body))
+          error(Twine("Can't relocate symbol ") + Body->getName());
+        uintX_t Offset = RI.r_offset;
+        uint32_t Type = RI.getType(EObj->isMips64EL());
+        uintX_t P = this->getVA() + C->getOutputSectionOff();
+        uintX_t SymVA = getSymVA<ELFT>(cast<DefinedRegular<ELFT>>(Body));
+        switch (Type) {
+        case llvm::ELF::R_X86_64_PC32:
+          support::endian::write32le(Base + Offset,
+                                     SymVA + (RI.r_addend - (P + Offset)));
+          break;
+        default:
+          llvm::errs() << Twine("unrecognized reloc ") + Twine(Type) << '\n';
+          break;
+        }
+      }
+    }
+  }
 }
 
 template <bool Is64Bits>
diff --git a/test/elf2/relocation.s b/test/elf2/relocation.s
new file mode 100644
index 0000000..1cfd45e
--- /dev/null
+++ b/test/elf2/relocation.s
@@ -0,0 +1,16 @@
+// RUN: llvm-mc -filetype=obj -triple=x86_64-pc-linux %s -o %t
+// RUN: lld -flavor gnu2 %t -o %t2
+// RUN: llvm-objdump -d %t2 | FileCheck %s
+// REQUIRES: x86
+
+
+.section       .text,"ax", at progbits,unique,1
+.global _start
+_start:
+  call lulz
+
+.section       .text,"ax", at progbits,unique,2
+.zero 4
+lulz:
+
+// CHECK: e8 04 00 00 00  callq   4


More information about the llvm-commits mailing list