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

Rafael EspĂ­ndola via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 08:29:14 PDT 2015


>> * Treating local symbols like regular symbols is incredibly wasteful.
>> They don't need the replacement logic.
>
> I agree, however we don't yet have a generic relocation processing
> API. The plan was to do this for now, and design a proper API when we
> know what we need and can share with the jit. This could be avoided
> now by checking in the relocation processing code if it's a local
> symbol and handling it differently, but that unnecessarily complicates
> code that's in the middle of development.

Close. The idea is to implement something good and then try to share
it with MCJIT.

In the attached patch I have
* Fixed style issues, like using auto when the type is not obvious.
* Made getSymVA static.
* Removed the local symbol support so that it can be properly designed
and implemented independently. For local symbols we don't need to
create a SymbolBody or even find out its name.
* Changed where the relocations are stored:

This one is something we will probably have to profile in the future.
There are at least 3 direct ways to do it:

* A single list of relocation sections + sort + binary search (what you did).
* Writing all the sections then walking all the relocations. Better
asymptotically, but not as cache friendly.
* Take advantage that we already allocate a SectionChunk for anything
that can be relocated and that normally there is only one relocation
section for each section. This is what the attached patch does. It is
probably faster and it is a smaller code change.

The diff is now
7 files changed, 96 insertions(+), 13 deletions(-)

This LGTM with at lest one testcase for a relocation section with an
invalid sh_info.

Cheers,
Rafael
-------------- next part --------------
diff --git a/ELF/Chunks.cpp b/ELF/Chunks.cpp
index 11186b4..29160da 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,19 @@ 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..1cb9721 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; }
@@ -47,13 +48,16 @@ public:
   void setOutputSection(OutputSection<ELFT> *O) { Out = O; }
   OutputSection<ELFT> *getOutputSection() const { return Out; }
 
+  // Relocation sections that refer to this one.
+  SmallVector<const Elf_Shdr *, 1> RelocSections;
+
 private:
   // The offset from beginning of the output sections this chunk was assigned
   // 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 457a78d..3502dfc 100644
--- a/ELF/InputFiles.cpp
+++ b/ELF/InputFiles.cpp
@@ -54,11 +54,20 @@ template <class ELFT> void elf2::ObjectFile<ELFT>::initializeChunks() {
     }
     case SHT_STRTAB:
     case SHT_NULL:
+      break;
     case SHT_RELA:
-    case SHT_REL:
+    case SHT_REL: {
+      uint32_t RelocatedSectionIndex = Sec.sh_info;
+      if (RelocatedSectionIndex >= Size)
+        error("Invalid relocated section index");
+      SectionChunk<ELFT> *RelocatedSection = Chunks[RelocatedSectionIndex];
+      if (!RelocatedSection)
+        error("Unsupported relocation reference");
+      RelocatedSection->RelocSections.push_back(&Sec);
       break;
+    }
     default:
-      Chunks[I] = new (Alloc) SectionChunk<ELFT>(this->getObj(), &Sec);
+      Chunks[I] = new (Alloc) SectionChunk<ELFT>(this, &Sec);
       break;
     }
     ++I;
diff --git a/ELF/InputFiles.h b/ELF/InputFiles.h
index 774166c..dc1c65b 100644
--- a/ELF/InputFiles.h
+++ b/ELF/InputFiles.h
@@ -91,6 +91,13 @@ public:
 
   ArrayRef<SectionChunk<ELFT> *> getChunks() { return Chunks; }
 
+  SymbolBody *getSymbolBody(uint32_t SymbolIndex) {
+    uint32_t FirstNonLocal = Symtab->sh_info;
+    if (SymbolIndex < FirstNonLocal)
+      return nullptr;
+    return SymbolBodies[SymbolIndex - FirstNonLocal]->getReplacement();
+  }
+
 private:
   void initializeChunks();
   void initializeSymbols();
diff --git a/ELF/Symbols.h b/ELF/Symbols.h
index 309c34f..50fc81a 100644
--- a/ELF/Symbols.h
+++ b/ELF/Symbols.h
@@ -63,6 +63,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
diff --git a/ELF/Writer.cpp b/ELF/Writer.cpp
index 38616f8..c42b0e6 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;
@@ -77,6 +79,8 @@ class lld::elf2::OutputSection final
     : public OutputSectionBase<ELFT::Is64Bits> {
 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) {}
 
@@ -215,9 +219,52 @@ void OutputSection<ELFT>::addChunk(SectionChunk<ELFT> *C) {
   this->Header.sh_size = Off;
 }
 
+template <class ELFT>
+static 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->Sym.st_value;
+}
+
 template <class ELFT> void OutputSection<ELFT>::writeTo(uint8_t *Buf) {
-  for (SectionChunk<ELFT> *C : Chunks)
+  for (SectionChunk<ELFT> *C : Chunks) {
     C->writeTo(Buf);
+    ObjectFile<ELFT> *File = C->getFile();
+    ELFFile<ELFT> *EObj = File->getObj();
+    uint8_t *Base = Buf + C->getOutputSectionOff();
+
+    // Iterate over all relocation sections that apply to this section.
+    for (const Elf_Shdr *RelSec : C->RelocSections) {
+      // Only support RELA for now.
+      if (RelSec->sh_type != SHT_RELA)
+        continue;
+      for (const Elf_Rela &RI : EObj->relas(RelSec)) {
+        uint32_t SymIndex = RI.getSymbol(EObj->isMips64EL());
+        SymbolBody *Body = File->getSymbolBody(SymIndex);
+        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..cbf7c78
--- /dev/null
+++ b/test/elf2/relocation.s
@@ -0,0 +1,17 @@
+// 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
+.global lulz
+lulz:
+
+// CHECK: e8 04 00 00 00  callq   4


More information about the llvm-commits mailing list