[llvm] 3f0841f - [jitlink] R_X86_64_PC32 support for the elf x86 jitlinker

Jared Wyles via llvm-commits llvm-commits at lists.llvm.org
Fri May 29 17:53:33 PDT 2020


Author: Jared Wyles
Date: 2020-05-30T10:53:18+10:00
New Revision: 3f0841f6d0a0eb86a1c36cc0c76931ae9d7bc77a

URL: https://github.com/llvm/llvm-project/commit/3f0841f6d0a0eb86a1c36cc0c76931ae9d7bc77a
DIFF: https://github.com/llvm/llvm-project/commit/3f0841f6d0a0eb86a1c36cc0c76931ae9d7bc77a.diff

LOG: [jitlink] R_X86_64_PC32 support for the elf x86 jitlinker

Summary:

Adding in our first relocation type, and all the required plumbing to support the rest in following patches

Differential Revision: https://reviews.llvm.org/D80613

Reviewer: lhames

Added: 
    

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h
    llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
    llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h
index ee43c356aebe..7860088f3569 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h
@@ -19,36 +19,33 @@ namespace llvm {
 namespace jitlink {
 
 namespace ELF_x86_64_Edges {
-
 enum ELFX86RelocationKind : Edge::Kind {
-  R_AMD64_NONE = Edge::FirstRelocation,
-  R_AMD64_64,
-  R_AMD64_PC32,
-  R_AMD64_GOT32,
-  R_AMD64_PLT32,
-  R_AMD64_COPY,
-  R_AMD64_GLOB_DAT,
-  R_AMD64_JUMP_SLOT,
-  R_AMD64_RELATIVE,
-  R_AMD64_GOTPCREL,
-  R_AMD64_32,
-  R_AMD64_32S,
-  R_AMD64_16,
-  R_AMD64_PC16,
-  R_AMD64_8,
-  R_AMD64_PC8,
-  R_AMD64_PC64,
-  R_AMD64_GOTOFF64,
-  R_AMD64_GOTPC32,
-  R_AMD64_SIZE32,
-  R_AMD64_SIZE64
+  Branch32 = Edge::FirstRelocation,
+  Branch32ToStub,
+  Pointer32,
+  Pointer64,
+  Pointer64Anon,
+  PCRel32,
+  PCRel32Minus1,
+  PCRel32Minus2,
+  PCRel32Minus4,
+  PCRel32Anon,
+  PCRel32Minus1Anon,
+  PCRel32Minus2Anon,
+  PCRel32Minus4Anon,
+  PCRel32GOTLoad,
+  PCRel32GOT,
+  PCRel32TLV,
+  Delta32,
+  Delta64,
+  NegDelta32,
+  NegDelta64,
 };
 
 } // end namespace ELF_x86_64_Edges
 
 /// jit-link the given object buffer, which must be a ELF x86-64 object file.
 void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx);
-StringRef getELFX86RelocationKindName(Edge::Kind R);
 } // end namespace jitlink
 } // end namespace llvm
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
index a7118eb9b563..505f03590b6b 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
@@ -24,12 +24,19 @@ static const char *CommonSectionName = "__common";
 
 namespace llvm {
 namespace jitlink {
+
 // This should become a template as the ELFFile is so a lot of this could become
 // generic
 class ELFLinkGraphBuilder_x86_64 {
 
 private:
   Section *CommonSection = nullptr;
+  // TODO hack to get this working
+  // Find a better way
+  using SymbolTable = object::ELFFile<object::ELF64LE>::Elf_Shdr;
+  // For now we just assume
+  std::map<int32_t, Symbol *> JITSymbolTable;
+
   Section &getCommonSection() {
     if (!CommonSection) {
       auto Prot = static_cast<sys::Memory::ProtectionFlags>(
@@ -39,10 +46,21 @@ class ELFLinkGraphBuilder_x86_64 {
     return *CommonSection;
   }
 
+  static Expected<ELF_x86_64_Edges::ELFX86RelocationKind>
+  getRelocationKind(const uint32_t Type) {
+    switch (Type) {
+    case ELF::R_X86_64_PC32:
+      return ELF_x86_64_Edges::ELFX86RelocationKind::PCRel32;
+    }
+    return make_error<JITLinkError>("Unsupported x86-64 relocation:" +
+                                    formatv("{0:d}", Type));
+  }
+
   std::unique_ptr<LinkGraph> G;
   // This could be a template
   const object::ELFFile<object::ELF64LE> &Obj;
   object::ELFFile<object::ELF64LE>::Elf_Shdr_Range sections;
+  SymbolTable SymTab;
 
   bool isRelocatable() { return Obj.getHeader()->e_type == llvm::ELF::ET_REL; }
 
@@ -88,11 +106,11 @@ class ELFLinkGraphBuilder_x86_64 {
         // FIXME: Read size.
         (void)Size;
 
-        if (auto NameOrErr = SymRef.getName(*StringTable)) {
+        if (auto NameOrErr = SymRef.getName(*StringTable))
           Name = *NameOrErr;
-        } else {
+        else
           return NameOrErr.takeError();
-        }
+
         LLVM_DEBUG({
           dbgs() << "  ";
           if (!Name)
@@ -157,12 +175,93 @@ class ELFLinkGraphBuilder_x86_64 {
         // Do this here because we have it, but move it into graphify later
         G->createContentBlock(section, StringRef(Data, Size), Address,
                               Alignment, 0);
+        if (SecRef.sh_type == ELF::SHT_SYMTAB)
+          // TODO: Dynamic?
+          SymTab = SecRef;
       }
     }
 
     return Error::success();
   }
 
+  Error addRelocations() {
+    LLVM_DEBUG(dbgs() << "Adding relocations\n");
+    // TODO a partern is forming of iterate some sections but only give me
+    // ones I am interested, i should abstract that concept some where
+    for (auto &SecRef : sections) {
+      if (SecRef.sh_type != ELF::SHT_RELA && SecRef.sh_type != ELF::SHT_REL)
+        continue;
+      // TODO can the elf obj file do this for me?
+      if (SecRef.sh_type == ELF::SHT_REL)
+        return make_error<llvm::StringError>("Shouldn't have REL in x64",
+                                             llvm::inconvertibleErrorCode());
+
+      auto RelSectName = Obj.getSectionName(&SecRef);
+      if (!RelSectName)
+        return RelSectName.takeError();
+      // Deal with .eh_frame later
+      if (*RelSectName == StringRef(".rela.eh_frame"))
+        continue;
+
+      auto UpdateSection = Obj.getSection(SecRef.sh_info);
+      if (!UpdateSection)
+        return UpdateSection.takeError();
+
+      auto UpdateSectionName = Obj.getSectionName(*UpdateSection);
+      if (!UpdateSectionName)
+        return UpdateSectionName.takeError();
+
+      auto JITSection = G->findSectionByName(*UpdateSectionName);
+      if (!JITSection)
+        return make_error<llvm::StringError>(
+            "Refencing a a section that wasn't added to graph" +
+                *UpdateSectionName,
+            llvm::inconvertibleErrorCode());
+
+      auto Relocations = Obj.relas(&SecRef);
+      if (!Relocations)
+        return Relocations.takeError();
+
+      for (const auto &Rela : *Relocations) {
+        auto Type = Rela.getType(false);
+
+        LLVM_DEBUG({
+          dbgs() << "Relocation Type: " << Type << "\n"
+                 << "Name: " << Obj.getRelocationTypeName(Type) << "\n";
+        });
+
+        auto Symbol = Obj.getRelocationSymbol(&Rela, &SymTab);
+        if (!Symbol)
+          return Symbol.takeError();
+
+        auto BlockToFix = *(JITSection->blocks().begin());
+        auto TargetSymbol = JITSymbolTable[(*Symbol)->st_shndx];
+        uint64_t Addend = Rela.r_addend;
+        JITTargetAddress FixupAddress =
+            (*UpdateSection)->sh_addr + Rela.r_offset;
+
+        LLVM_DEBUG({
+          dbgs() << "Processing relocation at "
+                 << format("0x%016" PRIx64, FixupAddress) << "\n";
+        });
+        auto Kind = getRelocationKind(Type);
+        if (!Kind)
+          return Kind.takeError();
+
+        LLVM_DEBUG({
+          Edge GE(*Kind, FixupAddress - BlockToFix->getAddress(), *TargetSymbol,
+                  Addend);
+          // TODO a mapping of KIND => type then call getRelocationTypeName4
+          printEdge(dbgs(), *BlockToFix, GE, StringRef(""));
+          dbgs() << "\n";
+        });
+        BlockToFix->addEdge(*Kind, FixupAddress - BlockToFix->getAddress(),
+                            *TargetSymbol, Addend);
+      }
+    }
+    return Error::success();
+  }
+
   Error graphifyRegularSymbols() {
 
     // TODO: ELF supports beyond SHN_LORESERVE,
@@ -219,11 +318,10 @@ class ELFLinkGraphBuilder_x86_64 {
         if (!Name)
           return Name.takeError();
         // TODO: weak and hidden
-        if (SymRef.isExternal()) {
+        if (SymRef.isExternal())
           bindings = {Linkage::Strong, Scope::Default};
-        } else {
+        else
           bindings = {Linkage::Strong, Scope::Local};
-        }
 
         if (SymRef.isDefined() &&
             (Type == ELF::STT_FUNC || Type == ELF::STT_OBJECT)) {
@@ -247,9 +345,10 @@ class ELFLinkGraphBuilder_x86_64 {
           auto B = *bs.begin();
           LLVM_DEBUG({ dbgs() << "  " << *Name << ": "; });
 
-          G->addDefinedSymbol(*B, SymRef.getValue(), *Name, SymRef.st_size,
-                              bindings.first, bindings.second,
-                              SymRef.getType() == ELF::STT_FUNC, false);
+          auto &S = G->addDefinedSymbol(
+              *B, SymRef.getValue(), *Name, SymRef.st_size, bindings.first,
+              bindings.second, SymRef.getType() == ELF::STT_FUNC, false);
+          JITSymbolTable[SymRef.st_shndx] = &S;
         }
         //TODO: The following has to be implmented.
         // leaving commented out to save time for future patchs
@@ -298,6 +397,9 @@ class ELFLinkGraphBuilder_x86_64 {
     if (auto Err = graphifyRegularSymbols())
       return std::move(Err);
 
+    if (auto Err = addRelocations())
+      return std::move(Err);
+
     return std::move(G);
   }
 };
@@ -311,9 +413,7 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
       : JITLinker(std::move(Ctx), std::move(PassConfig)) {}
 
 private:
-  StringRef getEdgeKindName(Edge::Kind R) const override {
-    return getELFX86RelocationKindName(R);
-  }
+  StringRef getEdgeKindName(Edge::Kind R) const override { return StringRef(); }
 
   Expected<std::unique_ptr<LinkGraph>>
   buildGraph(MemoryBufferRef ObjBuffer) override {
@@ -329,7 +429,17 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
   }
 
   Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
-    //TODO: add relocation handling
+    using namespace ELF_x86_64_Edges;
+    char *FixupPtr = BlockWorkingMem + E.getOffset();
+    JITTargetAddress FixupAddress = B.getAddress() + E.getOffset();
+    switch (E.getKind()) {
+
+    case ELFX86RelocationKind::PCRel32:
+      int64_t Value = E.getTarget().getAddress() + E.getAddend() - FixupAddress;
+      // verify
+      *(support::little32_t *)FixupPtr = Value;
+      break;
+    }
     return Error::success();
   }
 };
@@ -349,30 +459,5 @@ void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
 
   ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
 }
-
-StringRef getELFX86RelocationKindName(Edge::Kind R) {
-  // case R_AMD64_NONE:
-  //   return "None";
-  // case R_AMD64_PC32:
-  // case R_AMD64_GOT32:
-  // case R_AMD64_PLT32,
-  // R_AMD64_COPY,
-  // R_AMD64_GLOB_DAT,
-  // R_AMD64_JUMP_SLOT,
-  // R_AMD64_RELATIVE,
-  // R_AMD64_GOTPCREL,
-  // R_AMD64_32,
-  // R_AMD64_32S,
-  // R_AMD64_16,
-  // R_AMD64_PC16,
-  // R_AMD64_8,
-  // R_AMD64_PC8,
-  // R_AMD64_PC64,
-  // R_AMD64_GOTOFF64,
-  // R_AMD64_GOTPC32,
-  // R_AMD64_SIZE32,
-  // R_AMD64_SIZE64
-  return getGenericEdgeKindName(static_cast<Edge::Kind>(R));
-}
 } // end namespace jitlink
 } // end namespace llvm

diff  --git a/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s b/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s
index 12186e4f5433..20b26b1826ba 100644
--- a/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s
+++ b/llvm/test/ExecutionEngine/JITLink/X86/ELF_x86-64_relocations.s
@@ -1,20 +1,38 @@
 # RUN: rm -rf %t && mkdir -p %t
 # RUN: llvm-mc -triple=x86_64-unknown-linux -filetype=obj -o %t/elf_reloc.o %s
-# RUN: llvm-jitlink -noexec %t/elf_reloc.o
+# RUN: llvm-jitlink -noexec -check %s %t/elf_reloc.o
 #
 # Test standard ELF relocations.
 
         .text
         .file   "testcase.c"
+
+# Empty main entry point.
         .globl  main
         .p2align        4, 0x90
         .type   main, at function
 main:
-        movl    $42, %eax
         retq
 .Lfunc_end0:
         .size   main, .Lfunc_end0-main
 
+# Test PCRel32 / R_X86_64_PC32 handling.
+# jitlink-check: decode_operand(test_pcrel32, 4) = named_data - next_pc(test_pcrel32)
+        .globl  test_pcrel32
+        .p2align       4, 0x90
+        .type  test_pcrel32, at function
+test_pcrel32:
+        movl    named_data(%rip), %eax
+.Ltest_pcrel32_end:
+        .size   test_pcrel32, .Ltest_pcrel32_end-test_pcrel32
+
+        .type   named_data, at object
+        .data
+        .p2align        2
+named_data:
+        .long   42
+        .size   named_data, 4
+
         .ident  "clang version 10.0.0-4ubuntu1 "
         .section        ".note.GNU-stack","", at progbits
-        .addrsig
\ No newline at end of file
+        .addrsig


        


More information about the llvm-commits mailing list