[llvm] cc3115c - [JITLink][x86-64] Lift GOT, PLT table managers into x86_64.h; reuse for MachO.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 18 21:47:48 PDT 2021


Author: Lang Hames
Date: 2021-10-18T21:47:24-07:00
New Revision: cc3115cd1d35b7325d4f1d53f860048e32e82e43

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

LOG: [JITLink][x86-64] Lift GOT, PLT table managers into x86_64.h; reuse for MachO.

This lifts the global offset table and procedure linkage table builders out of
ELF_x86_64.h and into x86_64.h, renaming them with generic names
x86_64::GOTTableBuilder and x86_64::PLTTableBuilder. MachO_x86_64.cpp is updated
to use these classes instead of the older PerGraphGOTAndStubsBuilder tool.

Added: 
    

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/TableManager.h
    llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
    llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
    llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
    llvm/lib/ExecutionEngine/JITLink/x86_64.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/TableManager.h b/llvm/include/llvm/ExecutionEngine/JITLink/TableManager.h
index 2b502397a8dd9..c20f62d515ecb 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/TableManager.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/TableManager.h
@@ -38,7 +38,7 @@ template <typename TableManagerImplT> class TableManager {
     if (EntryI == Entries.end()) {
       auto &Entry = impl().createEntry(G, Target);
       DEBUG_WITH_TYPE("jitlink", {
-        dbgs() << "    Created" << impl().getTableName() << "entry for "
+        dbgs() << "    Created" << impl().getSectionName() << "entry for "
                << Target.getName() << ": " << Entry << "\n";
       });
       EntryI = Entries.insert(std::make_pair(Target.getName(), &Entry)).first;
@@ -46,7 +46,7 @@ template <typename TableManagerImplT> class TableManager {
 
     assert(EntryI != Entries.end() && "Could not get entry symbol");
     DEBUG_WITH_TYPE("jitlink", {
-      dbgs() << "    Using " << impl().getTableName() << " entry "
+      dbgs() << "    Using " << impl().getSectionName() << " entry "
              << *EntryI->second << "\n";
     });
     return *EntryI->second;

diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
index 1f6a861eb9d3a..3130ea3815344 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/x86_64.h
@@ -14,6 +14,7 @@
 #define LLVM_EXECUTIONENGINE_JITLINK_X86_64_H
 
 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/ExecutionEngine/JITLink/TableManager.h"
 
 #include <limits>
 
@@ -349,14 +350,6 @@ enum EdgeKind_x86_64 : Edge::Kind {
 /// only.
 const char *getEdgeKindName(Edge::Kind K);
 
-/// Optimize the GOT and Stub relocations if the edge target address is in range
-/// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range,
-/// then replace GOT load with lea
-/// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is
-/// in range, replace a indirect jump by plt stub with a direct jump to the
-/// target
-Error optimize_x86_64_GOTAndStubs(LinkGraph &G);
-
 /// Returns true if the given uint64_t value is in range for a uint32_t.
 inline bool isInRangeForImmU32(uint64_t Value) {
   return Value <= std::numeric_limits<uint32_t>::max();
@@ -523,6 +516,114 @@ inline Symbol &createAnonymousPointerJumpStub(LinkGraph &G,
       false);
 }
 
+/// Global Offset Table Builder.
+class GOTTableManager : public TableManager<GOTTableManager> {
+public:
+  static StringRef getSectionName() { return "$__GOT"; }
+
+  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
+    Edge::Kind KindToSet = Edge::Invalid;
+    switch (E.getKind()) {
+    case x86_64::Delta64FromGOT: {
+      // we need to make sure that the GOT section exists, but don't otherwise
+      // need to fix up this edge
+      getGOTSection(G);
+      return false;
+    }
+    case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
+      KindToSet = x86_64::PCRel32GOTLoadREXRelaxable;
+      break;
+    case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
+      KindToSet = x86_64::PCRel32GOTLoadRelaxable;
+      break;
+    case x86_64::RequestGOTAndTransformToDelta64:
+      KindToSet = x86_64::Delta64;
+      break;
+    case x86_64::RequestGOTAndTransformToDelta64FromGOT:
+      KindToSet = x86_64::Delta64FromGOT;
+      break;
+    case x86_64::RequestGOTAndTransformToDelta32:
+      KindToSet = x86_64::Delta32;
+      break;
+    default:
+      return false;
+    }
+    assert(KindToSet != Edge::Invalid &&
+           "Fell through switch, but no new kind to set");
+    DEBUG_WITH_TYPE("jitlink", {
+      dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
+             << formatv("{0:x}", B->getFixupAddress(E)) << " ("
+             << formatv("{0:x}", B->getAddress()) << " + "
+             << formatv("{0:x}", E.getOffset()) << ")\n";
+    });
+    E.setKind(KindToSet);
+    E.setTarget(getEntryForTarget(G, E.getTarget()));
+    return true;
+  }
+
+  Symbol &createEntry(LinkGraph &G, Symbol &Target) {
+    return createAnonymousPointer(G, getGOTSection(G), &Target);
+  }
+
+private:
+  Section &getGOTSection(LinkGraph &G) {
+    if (!GOTSection)
+      GOTSection = &G.createSection(getSectionName(), MemProt::Read);
+    return *GOTSection;
+  }
+
+  Section *GOTSection = nullptr;
+};
+
+/// Procedure Linkage Table Builder.
+class PLTTableManager : public TableManager<PLTTableManager> {
+public:
+  PLTTableManager(GOTTableManager &GOT) : GOT(GOT) {}
+
+  static StringRef getSectionName() { return "$__STUBS"; }
+
+  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
+    if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
+      DEBUG_WITH_TYPE("jitlink", {
+        dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
+               << formatv("{0:x}", B->getFixupAddress(E)) << " ("
+               << formatv("{0:x}", B->getAddress()) << " + "
+               << formatv("{0:x}", E.getOffset()) << ")\n";
+      });
+      // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to
+      // be optimized when the target is in-range.
+      E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
+      E.setTarget(getEntryForTarget(G, E.getTarget()));
+      return true;
+    }
+    return false;
+  }
+
+  Symbol &createEntry(LinkGraph &G, Symbol &Target) {
+    return createAnonymousPointerJumpStub(G, getStubsSection(G),
+                                          GOT.getEntryForTarget(G, Target));
+  }
+
+public:
+  Section &getStubsSection(LinkGraph &G) {
+    if (!PLTSection)
+      PLTSection =
+          &G.createSection(getSectionName(), MemProt::Read | MemProt::Exec);
+    return *PLTSection;
+  }
+
+  GOTTableManager &GOT;
+  Section *PLTSection = nullptr;
+};
+
+/// Optimize the GOT and Stub relocations if the edge target address is in range
+/// 1. PCRel32GOTLoadRelaxable. For this edge kind, if the target is in range,
+/// then replace GOT load with lea
+/// 2. BranchPCRel32ToPtrJumpStubRelaxable. For this edge kind, if the target is
+/// in range, replace a indirect jump by plt stub with a direct jump to the
+/// target
+Error optimizeGOTAndStubAccesses(LinkGraph &G);
+
 } // namespace x86_64
 } // 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 7153a3feccf4c..0cd111743edbe 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
@@ -21,7 +21,6 @@
 #include "EHFrameSupportImpl.h"
 #include "ELFLinkGraphBuilder.h"
 #include "JITLinkGeneric.h"
-#include "PerGraphGOTAndPLTStubsBuilder.h"
 
 #define DEBUG_TYPE "jitlink"
 
@@ -31,139 +30,15 @@ using namespace llvm::jitlink::ELF_x86_64_Edges;
 
 namespace {
 
-constexpr StringRef ELFGOTSectionName = "$__GOT";
 constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";
 constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO";
 
-class GOTTableManager_ELF_x86_64
-    : public TableManager<GOTTableManager_ELF_x86_64> {
-public:
-  static const uint8_t NullGOTEntryContent[8];
-
-  // Nice name for table
-  StringRef getTableName() { return "GOT"; }
-
-  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
-    Edge::Kind KindToSet = Edge::Invalid;
-    switch (E.getKind()) {
-    case x86_64::Delta64FromGOT: {
-      // we need to make sure that the GOT section exists, but don't otherwise
-      // need to fix up this edge
-      getGOTSection(G);
-      return false;
-    }
-    case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
-      KindToSet = x86_64::PCRel32GOTLoadREXRelaxable;
-      break;
-    case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
-      KindToSet = x86_64::PCRel32GOTLoadRelaxable;
-      break;
-    case x86_64::RequestGOTAndTransformToDelta64:
-      KindToSet = x86_64::Delta64;
-      break;
-    case x86_64::RequestGOTAndTransformToDelta64FromGOT:
-      KindToSet = x86_64::Delta64FromGOT;
-      break;
-    case x86_64::RequestGOTAndTransformToDelta32:
-      KindToSet = x86_64::Delta32;
-      break;
-    default:
-      return false;
-    }
-    assert(KindToSet != Edge::Invalid &&
-           "Fell through switch, but no new kind to set");
-    LLVM_DEBUG({
-      dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
-             << formatv("{0:x}", B->getFixupAddress(E)) << " ("
-             << formatv("{0:x}", B->getAddress()) << " + "
-             << formatv("{0:x}", E.getOffset()) << ")\n";
-    });
-    E.setKind(KindToSet);
-    E.setTarget(getEntryForTarget(G, E.getTarget()));
-    return true;
-  }
-
-  Symbol &createEntry(LinkGraph &G, Symbol &Target) {
-    auto &GOTEntryBlock = G.createContentBlock(
-        getGOTSection(G), getGOTEntryBlockContent(), 0, 8, 0);
-    GOTEntryBlock.addEdge(x86_64::Pointer64, 0, Target, 0);
-    return G.addAnonymousSymbol(GOTEntryBlock, 0, 8, false, false);
-  }
-
-private:
-  Section &getGOTSection(LinkGraph &G) {
-    if (!GOTSection)
-      GOTSection = &G.createSection(ELFGOTSectionName, MemProt::Read);
-    return *GOTSection;
-  }
-  ArrayRef<char> getGOTEntryBlockContent() const {
-    return {reinterpret_cast<const char *>(NullGOTEntryContent),
-            sizeof(NullGOTEntryContent)};
-  }
-  Section *GOTSection = nullptr;
-};
-const uint8_t GOTTableManager_ELF_x86_64::NullGOTEntryContent[8] = {
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-
-class PLTTableManager_ELF_x86_64
-    : public TableManager<PLTTableManager_ELF_x86_64> {
-public:
-  PLTTableManager_ELF_x86_64(GOTTableManager_ELF_x86_64 &GOTTable)
-      : GOTTable(GOTTable) {}
-
-  StringRef getTableName() { return "PLT"; }
-
-  static const uint8_t StubContent[6];
-  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
-    if (E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined()) {
-      LLVM_DEBUG({
-        dbgs() << "  Fixing " << G.getEdgeKindName(E.getKind()) << " edge at "
-               << formatv("{0:x}", B->getFixupAddress(E)) << " ("
-               << formatv("{0:x}", B->getAddress()) << " + "
-               << formatv("{0:x}", E.getOffset()) << ")\n";
-      });
-      // Set the edge kind to Branch32ToPtrJumpStubBypassable to enable it to
-      // be optimized when the target is in-range.
-      E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
-      E.setTarget(getEntryForTarget(G, E.getTarget()));
-      return true;
-    }
-    return false;
-  }
-
-  Symbol &createEntry(LinkGraph &G, Symbol &Target) {
-    auto &StubContentBlock = G.createContentBlock(
-        getStubsSection(G), getStubBlockContent(), 0, 1, 0);
-    // Re-use GOT entries for stub targets.
-    auto &GOTEntrySymbol = GOTTable.getEntryForTarget(G, Target);
-    StubContentBlock.addEdge(x86_64::Delta32, 2, GOTEntrySymbol, -4);
-    return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
-  }
-
-private:
-  Section &getStubsSection(LinkGraph &G) {
-    if (!StubsSection)
-      StubsSection =
-          &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec);
-    return *StubsSection;
-  }
-
-  ArrayRef<char> getStubBlockContent() {
-    return {reinterpret_cast<const char *>(StubContent), sizeof(StubContent)};
-  }
-
-  Section *StubsSection = nullptr;
-  GOTTableManager_ELF_x86_64 &GOTTable;
-};
-const uint8_t PLTTableManager_ELF_x86_64::StubContent[6] = {0xFF, 0x25, 0x00,
-                                                            0x00, 0x00, 0x00};
-
 class TLSInfoTableManager_ELF_x86_64
     : public TableManager<TLSInfoTableManager_ELF_x86_64> {
 public:
   static const uint8_t TLSInfoEntryContent[16];
 
-  StringRef getTableName() { return "TLSInfo"; }
+  static StringRef getSectionName() { return ELFTLSInfoSectionName; }
 
   bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
     if (E.getKind() == x86_64::RequestTLSDescInGOTAndTransformToDelta32) {
@@ -213,8 +88,8 @@ const uint8_t TLSInfoTableManager_ELF_x86_64::TLSInfoEntryContent[16] = {
 Error buildTables_ELF_x86_64(LinkGraph &G) {
   LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");
 
-  GOTTableManager_ELF_x86_64 GOT;
-  PLTTableManager_ELF_x86_64 PLT(GOT);
+  x86_64::GOTTableManager GOT;
+  x86_64::PLTTableManager PLT(GOT);
   TLSInfoTableManager_ELF_x86_64 TLSInfo;
   visitExistingEdges(G, GOT, PLT, TLSInfo);
   return Error::success();
@@ -412,7 +287,8 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
         createDefineExternalSectionStartAndEndSymbolsPass(
             [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {
               if (Sym.getName() == ELFGOTSymbolName)
-                if (auto *GOTSection = G.findSectionByName(ELFGOTSectionName)) {
+                if (auto *GOTSection = G.findSectionByName(
+                        x86_64::GOTTableManager::getSectionName())) {
                   GOTSymbol = &Sym;
                   return {*GOTSection, true};
                 }
@@ -431,7 +307,8 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
     // Otherwise look for a GOT section: If it already has a start symbol we'll
     // record it, otherwise we'll create our own.
     // If there's a GOT section but we didn't find an external GOT symbol...
-    if (auto *GOTSection = G.findSectionByName(ELFGOTSectionName)) {
+    if (auto *GOTSection =
+            G.findSectionByName(x86_64::GOTTableManager::getSectionName())) {
 
       // Check for an existing defined symbol.
       for (auto *Sym : GOTSection->symbols())
@@ -522,7 +399,7 @@ void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
             identifyELFSectionStartAndEndSymbols));
 
     // Add GOT/Stubs optimizer pass.
-    Config.PreFixupPasses.push_back(x86_64::optimize_x86_64_GOTAndStubs);
+    Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
   }
 
   if (auto Err = Ctx->modifyPassConfig(*G, Config))

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
index 40ded07fae6a5..18f92c8e47e45 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
@@ -420,79 +420,12 @@ class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
   }
 };
 
-class PerGraphGOTAndPLTStubsBuilder_MachO_x86_64
-    : public PerGraphGOTAndPLTStubsBuilder<
-          PerGraphGOTAndPLTStubsBuilder_MachO_x86_64> {
-public:
-
-  using PerGraphGOTAndPLTStubsBuilder<
-      PerGraphGOTAndPLTStubsBuilder_MachO_x86_64>::
-      PerGraphGOTAndPLTStubsBuilder;
-
-  bool isGOTEdgeToFix(Edge &E) const {
-    return E.getKind() == x86_64::RequestGOTAndTransformToDelta32 ||
-           E.getKind() ==
-               x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable;
-  }
-
-  Symbol &createGOTEntry(Symbol &Target) {
-    return x86_64::createAnonymousPointer(G, getGOTSection(), &Target);
-  }
-
-  void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
-    // Fix the edge kind.
-    switch (E.getKind()) {
-    case x86_64::RequestGOTAndTransformToDelta32:
-      E.setKind(x86_64::Delta32);
-      break;
-    case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
-      E.setKind(x86_64::PCRel32GOTLoadREXRelaxable);
-      break;
-    default:
-      llvm_unreachable("Not a GOT transform edge");
-    }
-    // Fix the target, leave the addend as-is.
-    E.setTarget(GOTEntry);
-  }
-
-  bool isExternalBranchEdge(Edge &E) {
-    return E.getKind() == x86_64::BranchPCRel32 && E.getTarget().isExternal();
-  }
-
-  Symbol &createPLTStub(Symbol &Target) {
-    return x86_64::createAnonymousPointerJumpStub(G, getStubsSection(),
-                                                  getGOTEntry(Target));
-  }
-
-  void fixPLTEdge(Edge &E, Symbol &Stub) {
-    assert(E.getKind() == x86_64::BranchPCRel32 && "Not a Branch32 edge?");
-    assert(E.getAddend() == 0 &&
-           "BranchPCRel32 edge has unexpected addend value");
-
-    // Set the edge kind to BranchPCRel32ToPtrJumpStubBypassable. We will use
-    // this to check for stub optimization opportunities in the
-    // optimizeMachO_x86_64_GOTAndStubs pass below.
-    E.setKind(x86_64::BranchPCRel32ToPtrJumpStubBypassable);
-    E.setTarget(Stub);
-  }
-
-private:
-  Section &getGOTSection() {
-    if (!GOTSection)
-      GOTSection = &G.createSection("$__GOT", MemProt::Read);
-    return *GOTSection;
-  }
-
-  Section &getStubsSection() {
-    if (!StubsSection)
-      StubsSection =
-          &G.createSection("$__STUBS", MemProt::Read | MemProt::Exec);
-    return *StubsSection;
-  }
-
-  Section *GOTSection = nullptr;
-  Section *StubsSection = nullptr;
-};
+Error buildGOTAndStubs_MachO_x86_64(LinkGraph &G) {
+  x86_64::GOTTableManager GOT;
+  x86_64::PLTTableManager PLT(GOT);
+  visitExistingEdges(G, GOT, PLT);
+  return Error::success();
+}
 
 } // namespace
 
@@ -543,11 +476,10 @@ void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
       Config.PrePrunePasses.push_back(markAllSymbolsLive);
 
     // Add an in-place GOT/Stubs pass.
-    Config.PostPrunePasses.push_back(
-        PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::asPass);
+    Config.PostPrunePasses.push_back(buildGOTAndStubs_MachO_x86_64);
 
     // Add GOT/Stubs optimizer pass.
-    Config.PreFixupPasses.push_back(x86_64::optimize_x86_64_GOTAndStubs);
+    Config.PreFixupPasses.push_back(x86_64::optimizeGOTAndStubAccesses);
   }
 
   if (auto Err = Ctx->modifyPassConfig(*G, Config))

diff  --git a/llvm/lib/ExecutionEngine/JITLink/x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/x86_64.cpp
index 8d95b33b2e5b4..48521280059da 100644
--- a/llvm/lib/ExecutionEngine/JITLink/x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/x86_64.cpp
@@ -71,7 +71,7 @@ const char NullPointerContent[PointerSize] = {0x00, 0x00, 0x00, 0x00,
 const char PointerJumpStubContent[6] = {
     static_cast<char>(0xFFu), 0x25, 0x00, 0x00, 0x00, 0x00};
 
-Error optimize_x86_64_GOTAndStubs(LinkGraph &G) {
+Error optimizeGOTAndStubAccesses(LinkGraph &G) {
   LLVM_DEBUG(dbgs() << "Optimizing GOT entries and stubs:\n");
 
   for (auto *B : G.blocks())


        


More information about the llvm-commits mailing list