[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