[lld] r246234 - [elf2] Add basic relocation support for x86-64.

Michael J. Spencer via llvm-commits llvm-commits at lists.llvm.org
Thu Aug 27 16:15:56 PDT 2015


Author: mspencer
Date: Thu Aug 27 18:15:56 2015
New Revision: 246234

URL: http://llvm.org/viewvc/llvm-project?rev=246234&view=rev
Log:
[elf2] Add basic relocation support for x86-64.

This currently doesn't handle local symbols.

Differential Revision: http://reviews.llvm.org/D11612

Added:
    lld/trunk/test/elf2/invalid-relocations.test
    lld/trunk/test/elf2/relocation.s
Modified:
    lld/trunk/ELF/Chunks.cpp
    lld/trunk/ELF/Chunks.h
    lld/trunk/ELF/InputFiles.cpp
    lld/trunk/ELF/InputFiles.h
    lld/trunk/ELF/Symbols.h
    lld/trunk/ELF/Writer.cpp

Modified: lld/trunk/ELF/Chunks.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Chunks.cpp?rev=246234&r1=246233&r2=246234&view=diff
==============================================================================
--- lld/trunk/ELF/Chunks.cpp (original)
+++ lld/trunk/ELF/Chunks.cpp Thu Aug 27 18:15:56 2015
@@ -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;
 }

Modified: lld/trunk/ELF/Chunks.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Chunks.h?rev=246234&r1=246233&r2=246234&view=diff
==============================================================================
--- lld/trunk/ELF/Chunks.h (original)
+++ lld/trunk/ELF/Chunks.h Thu Aug 27 18:15:56 2015
@@ -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;
 

Modified: lld/trunk/ELF/InputFiles.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.cpp?rev=246234&r1=246233&r2=246234&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.cpp (original)
+++ lld/trunk/ELF/InputFiles.cpp Thu Aug 27 18:15:56 2015
@@ -54,11 +54,20 @@ template <class ELFT> void elf2::ObjectF
     }
     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;

Modified: lld/trunk/ELF/InputFiles.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/InputFiles.h?rev=246234&r1=246233&r2=246234&view=diff
==============================================================================
--- lld/trunk/ELF/InputFiles.h (original)
+++ lld/trunk/ELF/InputFiles.h Thu Aug 27 18:15:56 2015
@@ -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();

Modified: lld/trunk/ELF/Symbols.h
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Symbols.h?rev=246234&r1=246233&r2=246234&view=diff
==============================================================================
--- lld/trunk/ELF/Symbols.h (original)
+++ lld/trunk/ELF/Symbols.h Thu Aug 27 18:15:56 2015
@@ -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

Modified: lld/trunk/ELF/Writer.cpp
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/ELF/Writer.cpp?rev=246234&r1=246233&r2=246234&view=diff
==============================================================================
--- lld/trunk/ELF/Writer.cpp (original)
+++ lld/trunk/ELF/Writer.cpp Thu Aug 27 18:15:56 2015
@@ -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(Secti
   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>

Added: lld/trunk/test/elf2/invalid-relocations.test
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/invalid-relocations.test?rev=246234&view=auto
==============================================================================
--- lld/trunk/test/elf2/invalid-relocations.test (added)
+++ lld/trunk/test/elf2/invalid-relocations.test Thu Aug 27 18:15:56 2015
@@ -0,0 +1,30 @@
+# RUN: yaml2obj -format elf %s -o %t
+# RUN: not lld -flavor gnu2 %t -o %tout 2>&1 | FileCheck %s
+
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  OSABI:           ELFOSABI_GNU
+  Type:            ET_REL
+  Machine:         EM_X86_64
+Sections:
+  - Name:            .text
+    Type:            SHT_PROGBITS
+    Flags:           [ SHF_ALLOC, SHF_EXECINSTR ]
+    AddressAlign:    0x0000000000000004
+    Content:         E800000000
+  - Name:            .rela.text
+    Type:            SHT_RELA
+    Info:            12 # Invalid index
+    Relocations:
+      - Offset:          0x0000000000000001
+        Symbol:          lulz
+        Type:            R_X86_64_PC32
+        Addend:          -4
+Symbols:
+  Global:
+    - Name:            lulz
+      Type:            STT_FUNC
+      Section:         .text
+
+# CHECK: Invalid relocated section index

Added: lld/trunk/test/elf2/relocation.s
URL: http://llvm.org/viewvc/llvm-project/lld/trunk/test/elf2/relocation.s?rev=246234&view=auto
==============================================================================
--- lld/trunk/test/elf2/relocation.s (added)
+++ lld/trunk/test/elf2/relocation.s Thu Aug 27 18:15:56 2015
@@ -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