[llvm] 0a74ec3 - [JITLink] Start laying the groundwork for ELF x86-64 large code model support.

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Sun Mar 21 21:03:36 PDT 2021


Author: Lang Hames
Date: 2021-03-21T20:56:47-07:00
New Revision: 0a74ec3299de83fe220c246ff5aa8f90d3364071

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

LOG: [JITLink] Start laying the groundwork for ELF x86-64 large code model support.

Introduces DefineExternalSectionStartAndEndSymbols.h, which defines a template
for a JITLink pass that transforms external symbols meeting a user-supplied
predicate into defined symbols pointing at the start and end of a Section
identified by the predicate. JITLink.h is updated with a new makeAbsolute
function to support this pass.

Also renames BasicGOTAndStubsBuilder to PerGraphGOTAndPLTStubsBuilder -- the new
name better describes the intent of this GOT and PLT stubs builder, and will
help to distinguish it from future GOT and PLT stub builders that build entries
that may be shared between multiple graphs.

Added: 
    llvm/lib/ExecutionEngine/JITLink/DefineExternalSectionStartAndEndSymbols.h
    llvm/lib/ExecutionEngine/JITLink/PerGraphGOTAndPLTStubsBuilder.h

Modified: 
    llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
    llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
    llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
    llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
    llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp

Removed: 
    llvm/lib/ExecutionEngine/JITLink/BasicGOTAndStubsBuilder.h


################################################################################
diff  --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
index 24c0a75ac53f..032cd58db968 100644
--- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
+++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h
@@ -122,11 +122,16 @@ class Addressable {
   void setAddress(JITTargetAddress Address) { this->Address = Address; }
 
   /// Returns true if this is a defined addressable, in which case you
-  /// can downcast this to a .
+  /// can downcast this to a Block.
   bool isDefined() const { return static_cast<bool>(IsDefined); }
   bool isAbsolute() const { return static_cast<bool>(IsAbsolute); }
 
 private:
+  void setAbsolute(bool IsAbsolute) {
+    assert(!IsDefined && "Cannot change the Absolute flag on a defined block");
+    this->IsAbsolute = IsAbsolute;
+  }
+
   JITTargetAddress Address = 0;
   uint64_t IsDefined : 1;
   uint64_t IsAbsolute : 1;
@@ -441,7 +446,7 @@ class Symbol {
   /// Returns true if the underlying addressable is an absolute symbol.
   bool isAbsolute() const {
     assert(Base && "Attempt to access null symbol");
-    return !Base->isDefined() && Base->isAbsolute();
+    return Base->isAbsolute();
   }
 
   /// Return the addressable that this symbol points to.
@@ -523,13 +528,20 @@ class Symbol {
 
 private:
   void makeExternal(Addressable &A) {
-    assert(!A.isDefined() && "Attempting to make external with defined block");
+    assert(!A.isDefined() && !A.isAbsolute() &&
+           "Attempting to make external with defined or absolute block");
     Base = &A;
     Offset = 0;
-    setLinkage(Linkage::Strong);
     setScope(Scope::Default);
     IsLive = 0;
-    // note: Size and IsCallable fields left unchanged.
+    // note: Size, Linkage and IsCallable fields left unchanged.
+  }
+
+  void makeAbsolute(Addressable &A) {
+    assert(!A.isDefined() && A.isAbsolute() &&
+           "Attempting to make absolute with defined or external block");
+    Base = &A;
+    Offset = 0;
   }
 
   void setBlock(Block &B) { Base = &B; }
@@ -916,6 +928,11 @@ class LinkGraph {
   /// an error will be emitted. Externals with weak linkage are permitted to
   /// be undefined, in which case they are assigned a value of 0.
   Symbol &addExternalSymbol(StringRef Name, uint64_t Size, Linkage L) {
+    assert(llvm::count_if(ExternalSymbols,
+                          [&](const Symbol *Sym) {
+                            return Sym->getName() == Name;
+                          }) == 0 &&
+           "Duplicate external symbol");
     auto &Sym =
         Symbol::constructExternal(Allocator.Allocate<Symbol>(),
                                   createAddressable(0, false), Name, Size, L);
@@ -926,6 +943,11 @@ class LinkGraph {
   /// Add an absolute symbol.
   Symbol &addAbsoluteSymbol(StringRef Name, JITTargetAddress Address,
                             uint64_t Size, Linkage L, Scope S, bool IsLive) {
+    assert(llvm::count_if(AbsoluteSymbols,
+                          [&](const Symbol *Sym) {
+                            return Sym->getName() == Name;
+                          }) == 0 &&
+           "Duplicate absolute symbol");
     auto &Sym = Symbol::constructAbsolute(Allocator.Allocate<Symbol>(),
                                           createAddressable(Address), Name,
                                           Size, L, S, IsLive);
@@ -937,6 +959,11 @@ class LinkGraph {
   Symbol &addCommonSymbol(StringRef Name, Scope S, Section &Section,
                           JITTargetAddress Address, uint64_t Size,
                           uint64_t Alignment, bool IsLive) {
+    assert(llvm::count_if(defined_symbols(),
+                          [&](const Symbol *Sym) {
+                            return Sym->getName() == Name;
+                          }) == 0 &&
+           "Duplicate defined symbol");
     auto &Sym = Symbol::constructCommon(
         Allocator.Allocate<Symbol>(),
         createBlock(Section, Size, Address, Alignment, 0), Name, Size, S,
@@ -959,6 +986,11 @@ class LinkGraph {
   Symbol &addDefinedSymbol(Block &Content, JITTargetAddress Offset,
                            StringRef Name, JITTargetAddress Size, Linkage L,
                            Scope S, bool IsCallable, bool IsLive) {
+    assert(llvm::count_if(defined_symbols(),
+                          [&](const Symbol *Sym) {
+                            return Sym->getName() == Name;
+                          }) == 0 &&
+           "Duplicate defined symbol");
     auto &Sym =
         Symbol::constructNamedDef(Allocator.Allocate<Symbol>(), Content, Offset,
                                   Name, Size, L, S, IsLive, IsCallable);
@@ -1009,28 +1041,63 @@ class LinkGraph {
         const_defined_symbol_iterator(Sections.end(), Sections.end()));
   }
 
-  /// Turn a defined symbol into an external one.
+  /// Make the given symbol external (must not already be external).
+  ///
+  /// Symbol size, linkage and callability will be left unchanged. Symbol scope
+  /// will be set to Default, and offset will be reset to 0.
   void makeExternal(Symbol &Sym) {
-    if (Sym.getAddressable().isAbsolute()) {
+    assert(!Sym.isExternal() && "Symbol is already external");
+    if (Sym.isAbsolute()) {
       assert(AbsoluteSymbols.count(&Sym) &&
              "Sym is not in the absolute symbols set");
+      assert(Sym.getOffset() == 0 && "Absolute not at offset 0");
       AbsoluteSymbols.erase(&Sym);
+      Sym.getAddressable().setAbsolute(false);
     } else {
       assert(Sym.isDefined() && "Sym is not a defined symbol");
       Section &Sec = Sym.getBlock().getSection();
       Sec.removeSymbol(Sym);
+      Sym.makeExternal(createAddressable(0, false));
     }
-    Sym.makeExternal(createAddressable(0, false));
     ExternalSymbols.insert(&Sym);
   }
 
-  /// Turn an external symbol into a defined one by attaching it to a block.
+  /// Make the given symbol an absolute with the given address (must not already
+  /// be absolute).
+  ///
+  /// Symbol size, linkage, scope, and callability, and liveness will be left
+  /// unchanged. Symbol offset will be reset to 0.
+  void makeAbsolute(Symbol &Sym, JITTargetAddress Address) {
+    assert(!Sym.isAbsolute() && "Symbol is already absolute");
+    if (Sym.isExternal()) {
+      assert(ExternalSymbols.count(&Sym) &&
+             "Sym is not in the absolute symbols set");
+      assert(Sym.getOffset() == 0 && "External is not at offset 0");
+      ExternalSymbols.erase(&Sym);
+      Sym.getAddressable().setAbsolute(true);
+    } else {
+      assert(Sym.isDefined() && "Sym is not a defined symbol");
+      Section &Sec = Sym.getBlock().getSection();
+      Sec.removeSymbol(Sym);
+      Sym.makeAbsolute(createAddressable(Address));
+    }
+    AbsoluteSymbols.insert(&Sym);
+  }
+
+  /// Turn an absolute or external symbol into a defined one by attaching it to
+  /// a block. Symbol must not already be defined.
   void makeDefined(Symbol &Sym, Block &Content, JITTargetAddress Offset,
                    JITTargetAddress Size, Linkage L, Scope S, bool IsLive) {
-    assert(!Sym.isDefined() && !Sym.isAbsolute() &&
-           "Sym is not an external symbol");
-    assert(ExternalSymbols.count(&Sym) && "Symbol is not in the externals set");
-    ExternalSymbols.erase(&Sym);
+    assert(!Sym.isDefined() && "Sym is already a defined symbol");
+    if (Sym.isAbsolute()) {
+      assert(AbsoluteSymbols.count(&Sym) &&
+             "Symbol is not in the absolutes set");
+      AbsoluteSymbols.erase(&Sym);
+    } else {
+      assert(ExternalSymbols.count(&Sym) &&
+             "Symbol is not in the externals set");
+      ExternalSymbols.erase(&Sym);
+    }
     Addressable &OldBase = *Sym.Base;
     Sym.setBlock(Content);
     Sym.setOffset(Offset);

diff  --git a/llvm/lib/ExecutionEngine/JITLink/BasicGOTAndStubsBuilder.h b/llvm/lib/ExecutionEngine/JITLink/BasicGOTAndStubsBuilder.h
deleted file mode 100644
index a67d8b25ef54..000000000000
--- a/llvm/lib/ExecutionEngine/JITLink/BasicGOTAndStubsBuilder.h
+++ /dev/null
@@ -1,107 +0,0 @@
-//===--- BasicGOTAndStubsBuilder.h - Generic GOT/Stub creation --*- C++ -*-===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-//
-// A base for simple GOT and stub creation.
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H
-#define LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H
-
-#include "llvm/ExecutionEngine/JITLink/JITLink.h"
-
-#define DEBUG_TYPE "jitlink"
-
-namespace llvm {
-namespace jitlink {
-
-template <typename BuilderImpl> class BasicGOTAndStubsBuilder {
-public:
-  BasicGOTAndStubsBuilder(LinkGraph &G) : G(G) {}
-
-  void run() {
-    // We're going to be adding new blocks, but we don't want to iterate over
-    // the newly added ones, so just copy the existing blocks out.
-    std::vector<Block *> Blocks(G.blocks().begin(), G.blocks().end());
-
-    LLVM_DEBUG(dbgs() << "Creating GOT entries and stubs:\n");
-
-    for (auto *B : Blocks)
-      for (auto &E : B->edges())
-        if (impl().isGOTEdgeToFix(E)) {
-          LLVM_DEBUG({
-            dbgs() << "  Updating GOT edge ";
-            printEdge(dbgs(), *B, E, "<target GOT>");
-            dbgs() << "\n";
-          });
-          impl().fixGOTEdge(E, getGOTEntrySymbol(E.getTarget()));
-        } else if (impl().isExternalBranchEdge(E)) {
-          LLVM_DEBUG({
-            dbgs() << "  Updating external branch edge ";
-            printEdge(dbgs(), *B, E, "<target PC-rel>");
-            dbgs() << "\n";
-          });
-          impl().fixExternalBranchEdge(E, getStubSymbol(E.getTarget()));
-        }
-  }
-
-protected:
-  Symbol &getGOTEntrySymbol(Symbol &Target) {
-    assert(Target.hasName() && "GOT edge cannot point to anonymous target");
-
-    auto GOTEntryI = GOTEntries.find(Target.getName());
-
-    // Build the entry if it doesn't exist.
-    if (GOTEntryI == GOTEntries.end()) {
-      auto &GOTEntry = impl().createGOTEntry(Target);
-      LLVM_DEBUG({
-        dbgs() << "    Created GOT entry for " << Target.getName() << ": "
-               << GOTEntry << "\n";
-      });
-      GOTEntryI =
-          GOTEntries.insert(std::make_pair(Target.getName(), &GOTEntry)).first;
-    }
-
-    assert(GOTEntryI != GOTEntries.end() && "Could not get GOT entry symbol");
-    LLVM_DEBUG(
-        { dbgs() << "    Using GOT entry " << *GOTEntryI->second << "\n"; });
-    return *GOTEntryI->second;
-  }
-
-  Symbol &getStubSymbol(Symbol &Target) {
-    assert(Target.hasName() &&
-           "External branch edge can not point to an anonymous target");
-    auto StubI = Stubs.find(Target.getName());
-
-    if (StubI == Stubs.end()) {
-      auto &StubSymbol = impl().createStub(Target);
-      LLVM_DEBUG({
-        dbgs() << "    Created stub for " << Target.getName() << ": "
-               << StubSymbol << "\n";
-      });
-      StubI = Stubs.insert(std::make_pair(Target.getName(), &StubSymbol)).first;
-    }
-
-    assert(StubI != Stubs.end() && "Count not get stub symbol");
-    LLVM_DEBUG({ dbgs() << "    Using stub " << *StubI->second << "\n"; });
-    return *StubI->second;
-  }
-
-  LinkGraph &G;
-
-private:
-  BuilderImpl &impl() { return static_cast<BuilderImpl &>(*this); }
-
-  DenseMap<StringRef, Symbol *> GOTEntries;
-  DenseMap<StringRef, Symbol *> Stubs;
-};
-
-} // end namespace jitlink
-} // end namespace llvm
-
-#endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H

diff  --git a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
index f613b9313505..bb3b62267106 100644
--- a/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/JITLink/CMakeLists.txt
@@ -1,8 +1,8 @@
 add_llvm_component_library(LLVMJITLink
+  EHFrameSupport.cpp
   JITLink.cpp
   JITLinkGeneric.cpp
   JITLinkMemoryManager.cpp
-  EHFrameSupport.cpp
 
   # Formats:
 

diff  --git a/llvm/lib/ExecutionEngine/JITLink/DefineExternalSectionStartAndEndSymbols.h b/llvm/lib/ExecutionEngine/JITLink/DefineExternalSectionStartAndEndSymbols.h
new file mode 100644
index 000000000000..2777bbaea9ff
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/DefineExternalSectionStartAndEndSymbols.h
@@ -0,0 +1,110 @@
+//===--------- DefineExternalSectionStartAndEndSymbols.h --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Utility class for recognizing external section start and end symbols and
+// transforming them into defined symbols for the start and end blocks of the
+// associated Section.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H
+#define LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H
+
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "jitlink"
+
+namespace llvm {
+namespace jitlink {
+
+struct SectionRangeSymbolDesc {
+  SectionRangeSymbolDesc() = default;
+  SectionRangeSymbolDesc(Section &Sec, bool IsStart)
+      : Sec(&Sec), IsStart(IsStart) {}
+  Section *Sec = nullptr;
+  bool IsStart = false;
+};
+
+/// Pass implementation for the createDefineExternalSectionStartAndEndSymbols
+/// function.
+template <typename SymbolIdentifierFunction>
+class DefineExternalSectionStartAndEndSymbols {
+public:
+  DefineExternalSectionStartAndEndSymbols(SymbolIdentifierFunction F)
+      : F(std::move(F)) {}
+
+  Error operator()(LinkGraph &G) {
+    for (auto *Sym : G.external_symbols()) {
+      SectionRangeSymbolDesc D = F(G, *Sym);
+      if (D.Sec) {
+        auto &SR = getSectionRange(*D.Sec);
+        if (D.IsStart) {
+          if (SR.isEmpty())
+            G.makeAbsolute(*Sym, 0);
+          else
+            G.makeDefined(*Sym, *SR.getFirstBlock(), 0, 0, Linkage::Strong,
+                          Scope::Local, false);
+        } else {
+          if (SR.isEmpty())
+            G.makeAbsolute(*Sym, 0);
+          else
+            G.makeDefined(*Sym, *SR.getLastBlock(),
+                          SR.getLastBlock()->getSize(), 0, Linkage::Strong,
+                          Scope::Local, false);
+        }
+      }
+    }
+    return Error::success();
+  }
+
+private:
+  SectionRange &getSectionRange(Section &Sec) {
+    auto I = SectionRanges.find(&Sec);
+    if (I == SectionRanges.end())
+      I = SectionRanges.insert(std::make_pair(&Sec, SectionRange(Sec))).first;
+    return I->second;
+  }
+
+  DenseMap<Section *, SectionRange> SectionRanges;
+  SymbolIdentifierFunction F;
+};
+
+/// Returns a JITLink pass (as a function class) that uses the given symbol
+/// identification function to identify external section start and end symbols
+/// (and their associated Section*s) and transform the identified externals
+/// into defined symbols pointing to the start of the first block in the
+/// section and the end of the last (start and end symbols for empty sections
+/// will be transformed into absolute symbols at address 0).
+///
+/// The identification function should be callable as
+///
+///   SectionRangeSymbolDesc (LinkGraph &G, Symbol &Sym)
+///
+/// If Sym is not a section range start or end symbol then a default
+/// constructed SectionRangeSymbolDesc should be returned. If Sym is a start
+/// symbol then SectionRangeSymbolDesc(Sec, true), where Sec is a reference to
+/// the target Section. If Sym is an end symbol then
+/// SectionRangeSymbolDesc(Sec, false) should be returned.
+///
+/// This pass should be run in the PostAllocationPass pipeline, at which point
+/// all blocks should have been assigned their final addresses.
+template <typename SymbolIdentifierFunction>
+DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>
+createDefineExternalSectionStartAndEndSymbolsPass(
+    SymbolIdentifierFunction &&F) {
+  return DefineExternalSectionStartAndEndSymbols<SymbolIdentifierFunction>(
+      std::forward<SymbolIdentifierFunction>(F));
+}
+
+} // end namespace jitlink
+} // end namespace llvm
+
+#undef DEBUG_TYPE
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_DEFINEEXTERNALSECTIONSTARTANDENDSYMBOLS_H

diff  --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
index 3532665cae53..8bba5dd77f8f 100644
--- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp
@@ -16,9 +16,10 @@
 #include "llvm/Object/ELFObjectFile.h"
 #include "llvm/Support/Endian.h"
 
-#include "BasicGOTAndStubsBuilder.h"
+#include "DefineExternalSectionStartAndEndSymbols.h"
 #include "EHFrameSupportImpl.h"
 #include "JITLinkGeneric.h"
+#include "PerGraphGOTAndPLTStubsBuilder.h"
 
 #define DEBUG_TYPE "jitlink"
 
@@ -28,14 +29,15 @@ using namespace llvm::jitlink::ELF_x86_64_Edges;
 
 namespace {
 
-class ELF_x86_64_GOTAndStubsBuilder
-    : public BasicGOTAndStubsBuilder<ELF_x86_64_GOTAndStubsBuilder> {
+class PerGraphGOTAndPLTStubsBuilder_ELF_x86_64
+    : public PerGraphGOTAndPLTStubsBuilder<
+          PerGraphGOTAndPLTStubsBuilder_ELF_x86_64> {
 public:
   static const uint8_t NullGOTEntryContent[8];
   static const uint8_t StubContent[6];
 
-  ELF_x86_64_GOTAndStubsBuilder(LinkGraph &G)
-      : BasicGOTAndStubsBuilder<ELF_x86_64_GOTAndStubsBuilder>(G) {}
+  using PerGraphGOTAndPLTStubsBuilder<
+      PerGraphGOTAndPLTStubsBuilder_ELF_x86_64>::PerGraphGOTAndPLTStubsBuilder;
 
   bool isGOTEdgeToFix(Edge &E) const {
     return E.getKind() == PCRel32GOT || E.getKind() == PCRel32GOTLoad;
@@ -66,16 +68,16 @@ class ELF_x86_64_GOTAndStubsBuilder
     return E.getKind() == Branch32 && !E.getTarget().isDefined();
   }
 
-  Symbol &createStub(Symbol &Target) {
+  Symbol &createPLTStub(Symbol &Target) {
     auto &StubContentBlock =
         G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
     // Re-use GOT entries for stub targets.
-    auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
+    auto &GOTEntrySymbol = getGOTEntry(Target);
     StubContentBlock.addEdge(PCRel32, 2, GOTEntrySymbol, -4);
     return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
   }
 
-  void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
+  void fixPLTEdge(Edge &E, Symbol &Stub) {
     assert(E.getKind() == Branch32 && "Not a Branch32 edge?");
 
     // Set the edge kind to Branch32ToStub. We will use this to check for stub
@@ -115,6 +117,8 @@ class ELF_x86_64_GOTAndStubsBuilder
   Section *StubsSection = nullptr;
 };
 
+StringRef ELFGOTSectionName = "$__GOT";
+
 const char *const DwarfSectionNames[] = {
 #define HANDLE_DWARF_SECTION(ENUM_NAME, ELF_NAME, CMDLINE_NAME, OPTION)        \
   ELF_NAME,
@@ -124,9 +128,9 @@ const char *const DwarfSectionNames[] = {
 
 } // namespace
 
-const uint8_t ELF_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-const uint8_t ELF_x86_64_GOTAndStubsBuilder::StubContent[6] = {
+const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_x86_64::NullGOTEntryContent[8] =
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+const uint8_t PerGraphGOTAndPLTStubsBuilder_ELF_x86_64::StubContent[6] = {
     0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
 
 static const char *CommonSectionName = "__common";
@@ -172,9 +176,10 @@ static Error optimizeELF_x86_64_GOTAndStubs(LinkGraph &G) {
         }
       } else if (E.getKind() == Branch32ToStub) {
         auto &StubBlock = E.getTarget().getBlock();
-        assert(StubBlock.getSize() ==
-                   sizeof(ELF_x86_64_GOTAndStubsBuilder::StubContent) &&
-               "Stub block should be stub sized");
+        assert(
+            StubBlock.getSize() ==
+                sizeof(PerGraphGOTAndPLTStubsBuilder_ELF_x86_64::StubContent) &&
+            "Stub block should be stub sized");
         assert(StubBlock.edges_size() == 1 &&
                "Stub block should only have one outgoing edge");
 
@@ -217,6 +222,7 @@ 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;
@@ -773,6 +779,27 @@ createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer) {
       .buildGraph();
 }
 
+static SectionRangeSymbolDesc
+identifyELFSectionStartAndEndSymbols(LinkGraph &G, Symbol &Sym) {
+  constexpr StringRef StartSymbolPrefix = "__start";
+  constexpr StringRef EndSymbolPrefix = "__end";
+
+  auto SymName = Sym.getName();
+  if (SymName.startswith(StartSymbolPrefix)) {
+    if (auto *Sec =
+            G.findSectionByName(SymName.drop_front(StartSymbolPrefix.size())))
+      return {*Sec, true};
+  } else if (SymName.startswith(EndSymbolPrefix)) {
+    if (auto *Sec =
+            G.findSectionByName(SymName.drop_front(EndSymbolPrefix.size())))
+      return {*Sec, false};
+  } else if (SymName == "_GLOBAL_OFFSET_TABLE_") {
+    if (auto *GOTSec = G.findSectionByName(ELFGOTSectionName))
+      return {*GOTSec, true};
+  }
+  return {};
+}
+
 void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
                      std::unique_ptr<JITLinkContext> Ctx) {
   PassConfiguration Config;
@@ -792,13 +819,16 @@ void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
       Config.PrePrunePasses.push_back(markAllSymbolsLive);
 
     // Add an in-place GOT/Stubs pass.
-    Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
-      ELF_x86_64_GOTAndStubsBuilder(G).run();
-      return Error::success();
-    });
+    Config.PostPrunePasses.push_back(
+        PerGraphGOTAndPLTStubsBuilder_ELF_x86_64::asPass);
 
     // Add GOT/Stubs optimizer pass.
     Config.PreFixupPasses.push_back(optimizeELF_x86_64_GOTAndStubs);
+
+    // Resolve any external section start / end symbols.
+    Config.PreFixupPasses.push_back(
+        createDefineExternalSectionStartAndEndSymbolsPass(
+            identifyELFSectionStartAndEndSymbols));
   }
 
   if (auto Err = Ctx->modifyPassConfig(*G, Config))

diff  --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
index d0a50d84007d..344334a61720 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp
@@ -12,8 +12,8 @@
 
 #include "llvm/ExecutionEngine/JITLink/MachO_arm64.h"
 
-#include "BasicGOTAndStubsBuilder.h"
 #include "MachOLinkGraphBuilder.h"
+#include "PerGraphGOTAndPLTStubsBuilder.h"
 
 #define DEBUG_TYPE "jitlink"
 
@@ -405,11 +405,12 @@ class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
   unsigned NumSymbols = 0;
 };
 
-class MachO_arm64_GOTAndStubsBuilder
-    : public BasicGOTAndStubsBuilder<MachO_arm64_GOTAndStubsBuilder> {
+class PerGraphGOTAndPLTStubsBuilder_MachO_arm64
+    : public PerGraphGOTAndPLTStubsBuilder<
+          PerGraphGOTAndPLTStubsBuilder_MachO_arm64> {
 public:
-  MachO_arm64_GOTAndStubsBuilder(LinkGraph &G)
-      : BasicGOTAndStubsBuilder<MachO_arm64_GOTAndStubsBuilder>(G) {}
+  using PerGraphGOTAndPLTStubsBuilder<
+      PerGraphGOTAndPLTStubsBuilder_MachO_arm64>::PerGraphGOTAndPLTStubsBuilder;
 
   bool isGOTEdgeToFix(Edge &E) const {
     return (E.getKind() == GOTPage21 || E.getKind() == GOTPageOffset12 ||
@@ -439,16 +440,16 @@ class MachO_arm64_GOTAndStubsBuilder
     return E.getKind() == Branch26 && !E.getTarget().isDefined();
   }
 
-  Symbol &createStub(Symbol &Target) {
+  Symbol &createPLTStub(Symbol &Target) {
     auto &StubContentBlock =
         G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
     // Re-use GOT entries for stub targets.
-    auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
+    auto &GOTEntrySymbol = getGOTEntry(Target);
     StubContentBlock.addEdge(LDRLiteral19, 0, GOTEntrySymbol, 0);
     return G.addAnonymousSymbol(StubContentBlock, 0, 8, true, false);
   }
 
-  void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
+  void fixPLTEdge(Edge &E, Symbol &Stub) {
     assert(E.getKind() == Branch26 && "Not a Branch32 edge?");
     assert(E.getAddend() == 0 && "Branch32 edge has non-zero addend?");
     E.setTarget(Stub);
@@ -486,9 +487,10 @@ class MachO_arm64_GOTAndStubsBuilder
   Section *StubsSection = nullptr;
 };
 
-const uint8_t MachO_arm64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-const uint8_t MachO_arm64_GOTAndStubsBuilder::StubContent[8] = {
+const uint8_t
+    PerGraphGOTAndPLTStubsBuilder_MachO_arm64::NullGOTEntryContent[8] = {
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_arm64::StubContent[8] = {
     0x10, 0x00, 0x00, 0x58, // LDR x16, <literal>
     0x00, 0x02, 0x1f, 0xd6  // BR  x16
 };
@@ -684,10 +686,8 @@ void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
       Config.PrePrunePasses.push_back(markAllSymbolsLive);
 
     // Add an in-place GOT/Stubs pass.
-    Config.PostPrunePasses.push_back([](LinkGraph &G) -> Error {
-      MachO_arm64_GOTAndStubsBuilder(G).run();
-      return Error::success();
-    });
+    Config.PostPrunePasses.push_back(
+        PerGraphGOTAndPLTStubsBuilder_MachO_arm64::asPass);
   }
 
   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 e0f5ea595c2b..cf872db51c5c 100644
--- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
+++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp
@@ -13,8 +13,8 @@
 #include "llvm/ExecutionEngine/JITLink/MachO_x86_64.h"
 #include "llvm/ExecutionEngine/JITLink/x86_64.h"
 
-#include "BasicGOTAndStubsBuilder.h"
 #include "MachOLinkGraphBuilder.h"
+#include "PerGraphGOTAndPLTStubsBuilder.h"
 
 #define DEBUG_TYPE "jitlink"
 
@@ -414,14 +414,16 @@ class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
   }
 };
 
-class MachO_x86_64_GOTAndStubsBuilder
-    : public BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder> {
+class PerGraphGOTAndPLTStubsBuilder_MachO_x86_64
+    : public PerGraphGOTAndPLTStubsBuilder<
+          PerGraphGOTAndPLTStubsBuilder_MachO_x86_64> {
 public:
   static const uint8_t NullGOTEntryContent[8];
   static const uint8_t StubContent[6];
 
-  MachO_x86_64_GOTAndStubsBuilder(LinkGraph &G)
-      : BasicGOTAndStubsBuilder<MachO_x86_64_GOTAndStubsBuilder>(G) {}
+  using PerGraphGOTAndPLTStubsBuilder<
+      PerGraphGOTAndPLTStubsBuilder_MachO_x86_64>::
+      PerGraphGOTAndPLTStubsBuilder;
 
   bool isGOTEdgeToFix(Edge &E) const {
     return E.getKind() == x86_64::RequestGOTAndTransformToDelta32 ||
@@ -456,16 +458,16 @@ class MachO_x86_64_GOTAndStubsBuilder
     return E.getKind() == x86_64::BranchPCRel32 && E.getTarget().isExternal();
   }
 
-  Symbol &createStub(Symbol &Target) {
+  Symbol &createPLTStub(Symbol &Target) {
     auto &StubContentBlock =
         G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
     // Re-use GOT entries for stub targets.
-    auto &GOTEntrySymbol = getGOTEntrySymbol(Target);
+    auto &GOTEntrySymbol = getGOTEntry(Target);
     StubContentBlock.addEdge(x86_64::Delta32, 2, GOTEntrySymbol, -4);
     return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
   }
 
-  void fixExternalBranchEdge(Edge &E, Symbol &Stub) {
+  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");
@@ -507,9 +509,10 @@ class MachO_x86_64_GOTAndStubsBuilder
   Section *StubsSection = nullptr;
 };
 
-const uint8_t MachO_x86_64_GOTAndStubsBuilder::NullGOTEntryContent[8] = {
-    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
-const uint8_t MachO_x86_64_GOTAndStubsBuilder::StubContent[6] = {
+const uint8_t
+    PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::NullGOTEntryContent[8] = {
+        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+const uint8_t PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::StubContent[6] = {
     0xFF, 0x25, 0x00, 0x00, 0x00, 0x00};
 } // namespace
 
@@ -556,9 +559,11 @@ static Error optimizeMachO_x86_64_GOTAndStubs(LinkGraph &G) {
         }
       } else if (E.getKind() == x86_64::BranchPCRel32ToPtrJumpStubRelaxable) {
         auto &StubBlock = E.getTarget().getBlock();
-        assert(StubBlock.getSize() ==
-                   sizeof(MachO_x86_64_GOTAndStubsBuilder::StubContent) &&
-               "Stub block should be stub sized");
+        assert(
+            StubBlock.getSize() ==
+                sizeof(
+                    PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::StubContent) &&
+            "Stub block should be stub sized");
         assert(StubBlock.edges_size() == 1 &&
                "Stub block should only have one outgoing edge");
 
@@ -634,10 +639,8 @@ 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([](LinkGraph &G) -> Error {
-      MachO_x86_64_GOTAndStubsBuilder(G).run();
-      return Error::success();
-    });
+    Config.PostPrunePasses.push_back(
+        PerGraphGOTAndPLTStubsBuilder_MachO_x86_64::asPass);
 
     // Add GOT/Stubs optimizer pass.
     Config.PreFixupPasses.push_back(optimizeMachO_x86_64_GOTAndStubs);

diff  --git a/llvm/lib/ExecutionEngine/JITLink/PerGraphGOTAndPLTStubsBuilder.h b/llvm/lib/ExecutionEngine/JITLink/PerGraphGOTAndPLTStubsBuilder.h
new file mode 100644
index 000000000000..6e9df9c75a65
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/JITLink/PerGraphGOTAndPLTStubsBuilder.h
@@ -0,0 +1,126 @@
+//===--------------- PerGraphGOTAndPLTStubBuilder.h -------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Construct GOT and PLT entries for each graph.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H
+#define LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H
+
+#include "llvm/ExecutionEngine/JITLink/JITLink.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "jitlink"
+
+namespace llvm {
+namespace jitlink {
+
+/// Per-object GOT and PLT Stub builder.
+///
+/// Constructs GOT entries and PLT stubs in every graph for referenced symbols.
+/// Building these blocks in every graph is likely to lead to duplicate entries
+/// in the JITLinkDylib, but allows graphs to be trivially removed independently
+/// without affecting other graphs (since those other graphs will have their own
+/// copies of any required entries).
+template <typename BuilderImplT>
+class PerGraphGOTAndPLTStubsBuilder {
+public:
+  PerGraphGOTAndPLTStubsBuilder(LinkGraph &G) : G(G) {}
+
+  static Error asPass(LinkGraph &G) { return BuilderImplT(G).run(); }
+
+  Error run() {
+    LLVM_DEBUG(dbgs() << "Running Per-Graph GOT and Stubs builder:\n");
+
+    // We're going to be adding new blocks, but we don't want to iterate over
+    // the new ones, so build a worklist.
+    std::vector<Block *> Worklist(G.blocks().begin(), G.blocks().end());
+
+    for (auto *B : Worklist)
+      for (auto &E : B->edges()) {
+        if (impl().isGOTEdgeToFix(E)) {
+          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";
+          });
+          impl().fixGOTEdge(E, getGOTEntry(E.getTarget()));
+        } else if (impl().isExternalBranchEdge(E)) {
+          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";
+          });
+          impl().fixPLTEdge(E, getPLTStub(E.getTarget()));
+        }
+      }
+
+    return Error::success();
+  }
+
+protected:
+  Symbol &getGOTEntry(Symbol &Target) {
+    assert(Target.hasName() && "GOT edge cannot point to anonymous target");
+
+    auto GOTEntryI = GOTEntries.find(Target.getName());
+
+    // Build the entry if it doesn't exist.
+    if (GOTEntryI == GOTEntries.end()) {
+      auto &GOTEntry = impl().createGOTEntry(Target);
+      LLVM_DEBUG({
+        dbgs() << "    Created GOT entry for " << Target.getName() << ": "
+               << GOTEntry << "\n";
+      });
+      GOTEntryI =
+          GOTEntries.insert(std::make_pair(Target.getName(), &GOTEntry)).first;
+    }
+
+    assert(GOTEntryI != GOTEntries.end() && "Could not get GOT entry symbol");
+    LLVM_DEBUG(
+        { dbgs() << "    Using GOT entry " << *GOTEntryI->second << "\n"; });
+    return *GOTEntryI->second;
+  }
+
+  Symbol &getPLTStub(Symbol &Target) {
+    assert(Target.hasName() &&
+           "External branch edge can not point to an anonymous target");
+    auto StubI = PLTStubs.find(Target.getName());
+
+    if (StubI == PLTStubs.end()) {
+      auto &StubSymbol = impl().createPLTStub(Target);
+      LLVM_DEBUG({
+        dbgs() << "    Created PLT stub for " << Target.getName() << ": "
+               << StubSymbol << "\n";
+      });
+      StubI =
+          PLTStubs.insert(std::make_pair(Target.getName(), &StubSymbol)).first;
+    }
+
+    assert(StubI != PLTStubs.end() && "Count not get stub symbol");
+    LLVM_DEBUG({ dbgs() << "    Using PLT stub " << *StubI->second << "\n"; });
+    return *StubI->second;
+  }
+
+  LinkGraph &G;
+
+private:
+  BuilderImplT &impl() { return static_cast<BuilderImplT &>(*this); }
+
+  DenseMap<StringRef, Symbol *> GOTEntries;
+  DenseMap<StringRef, Symbol *> PLTStubs;
+};
+
+} // end namespace jitlink
+} // end namespace llvm
+
+#undef DEBUG_TYPE
+
+#endif // LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H


        


More information about the llvm-commits mailing list