Revert "[JITLink][NFC] Add TableManager to replace PerGraph...Builder pass"

This reverts commit 50a278c2ae.
This commit is contained in:
luxufan 2021-10-06 21:33:04 +08:00
parent f6fa95b77f
commit b384736b20
4 changed files with 220 additions and 252 deletions

View File

@ -1688,30 +1688,6 @@ Error markAllSymbolsLive(LinkGraph &G);
Error makeTargetOutOfRangeError(const LinkGraph &G, const Block &B,
const Edge &E);
static void visitEdge(LinkGraph &G, Block *B, Edge &E) {}
template <typename FixerT, typename... FixerTs>
static void visitEdge(LinkGraph &G, Block *B, Edge &E, FixerT &&Fixer,
FixerTs &&...Fixers) {
if (!Fixer.visitEdge(G, B, E))
visitEdge(G, B, E, std::forward<FixerTs>(Fixers)...);
}
/// Visits edges exist in graph by Fixers.
///
/// Note: that if a fixer fixes the edge successfully,
/// the rest of the fixers will not visit this edge.
template <typename... FixerTs>
void visitExistingEdges(LinkGraph &G, FixerTs &&...Fixers) {
// 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())
visitEdge(G, B, E, std::forward<FixerTs>(Fixers)...);
}
/// Create a LinkGraph from the given object buffer.
///
/// Note: The graph does not take ownership of the underlying buffer, nor copy

View File

@ -21,7 +21,7 @@
#include "ELFLinkGraphBuilder.h"
#include "JITLinkGeneric.h"
#include "PerGraphGOTAndPLTStubsBuilder.h"
#include "TableManager.h"
#include "PerGraphTLSInfoEntryBuilder.h"
#define DEBUG_TYPE "jitlink"
@ -35,109 +35,148 @@ 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> {
class PerGraphTLSInfoBuilder_ELF_x86_64
: public PerGraphTLSInfoEntryBuilder<PerGraphTLSInfoBuilder_ELF_x86_64> {
public:
static const uint8_t NullGOTEntryContent[8];
static const uint8_t TLSInfoEntryContent[16];
using PerGraphTLSInfoEntryBuilder<
PerGraphTLSInfoBuilder_ELF_x86_64>::PerGraphTLSInfoEntryBuilder;
// Nice name for table
StringRef getTableName() { return "GOT"; }
bool fixEdgeKind(LinkGraph &G, Block *B, Edge &E) {
Edge::Kind KindToSet = E.getKind();
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;
}
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);
return true;
bool isTLSEdgeToFix(Edge &E) {
return E.getKind() == x86_64::RequestTLSDescInGOTAndTransformToDelta32;
}
Symbol &createEntry(LinkGraph &G, Symbol &Target) {
Symbol &createTLSInfoEntry(Symbol &Target) {
// the TLS Info entry's key value will be written by the fixTLVSectionByName
// pass, so create mutable content.
auto &TLSInfoEntry = G.createMutableContentBlock(
getTLSInfoSection(), G.allocateContent(getTLSInfoEntryContent()), 0, 8,
0);
TLSInfoEntry.addEdge(x86_64::Pointer64, 8, Target, 0);
return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
}
void fixTLSEdge(Edge &E, Symbol &Target) {
if (E.getKind() == x86_64::RequestTLSDescInGOTAndTransformToDelta32) {
E.setTarget(Target);
E.setKind(x86_64::Delta32);
}
}
Section &getTLSInfoSection() const {
if (!TLSInfoSection)
TLSInfoSection =
&G.createSection(ELFTLSInfoSectionName, sys::Memory::MF_READ);
return *TLSInfoSection;
}
private:
ArrayRef<char> getTLSInfoEntryContent() {
return {reinterpret_cast<const char *>(TLSInfoEntryContent),
sizeof(TLSInfoEntryContent)};
}
mutable Section *TLSInfoSection = nullptr;
};
const uint8_t PerGraphTLSInfoBuilder_ELF_x86_64::TLSInfoEntryContent[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/
};
class PerGraphGOTAndPLTStubsBuilder_ELF_x86_64
: public PerGraphGOTAndPLTStubsBuilder<
PerGraphGOTAndPLTStubsBuilder_ELF_x86_64> {
public:
static const uint8_t NullGOTEntryContent[8];
static const uint8_t StubContent[6];
using PerGraphGOTAndPLTStubsBuilder<
PerGraphGOTAndPLTStubsBuilder_ELF_x86_64>::PerGraphGOTAndPLTStubsBuilder;
bool isGOTEdgeToFix(Edge &E) const {
if (E.getKind() == x86_64::Delta64FromGOT) {
// We need to make sure that the GOT section exists, but don't otherwise
// need to fix up this edge.
getGOTSection();
return false;
}
return E.getKind() == x86_64::RequestGOTAndTransformToDelta32 ||
E.getKind() == x86_64::RequestGOTAndTransformToDelta64 ||
E.getKind() ==
x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable ||
E.getKind() == x86_64::RequestGOTAndTransformToDelta64FromGOT ||
E.getKind() ==
x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable;
}
Symbol &createGOTEntry(Symbol &Target) {
auto &GOTEntryBlock = G.createContentBlock(
getGOTSection(G), getGOTEntryBlockContent(), 0, 8, 0);
getGOTSection(), 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, sys::Memory::MF_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 fixEdgeKind(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);
return true;
void fixGOTEdge(Edge &E, Symbol &GOTEntry) {
// If this is a PCRel32GOT/PCRel64GOT then change it to an ordinary
// PCRel32/PCRel64. If it is a PCRel32GOTLoad then leave it as-is for now:
// We will use the kind to check for GOT optimization opportunities in the
// optimizeMachO_x86_64_GOTAndStubs pass below.
// If it's a GOT64 leave it as is.
switch (E.getKind()) {
case x86_64::RequestGOTAndTransformToPCRel32GOTLoadREXRelaxable:
E.setKind(x86_64::PCRel32GOTLoadREXRelaxable);
break;
case x86_64::RequestGOTAndTransformToPCRel32GOTLoadRelaxable:
E.setKind(x86_64::PCRel32GOTLoadRelaxable);
break;
case x86_64::RequestGOTAndTransformToDelta64:
E.setKind(x86_64::Delta64);
break;
case x86_64::RequestGOTAndTransformToDelta64FromGOT:
E.setKind(x86_64::Delta64FromGOT);
break;
case x86_64::RequestGOTAndTransformToDelta32:
E.setKind(x86_64::Delta32);
break;
default:
llvm_unreachable("Unexpected GOT edge kind");
}
return false;
E.setTarget(GOTEntry);
// Leave the edge addend as-is.
}
Symbol &createEntry(LinkGraph &G, Symbol &Target) {
auto &StubContentBlock = G.createContentBlock(
getStubsSection(G), getStubBlockContent(), 0, 1, 0);
bool isExternalBranchEdge(Edge &E) {
return E.getKind() == x86_64::BranchPCRel32 && !E.getTarget().isDefined();
}
Symbol &createPLTStub(Symbol &Target) {
auto &StubContentBlock =
G.createContentBlock(getStubsSection(), getStubBlockContent(), 0, 1, 0);
// Re-use GOT entries for stub targets.
auto &GOTEntrySymbol = GOTTable.getEntryForTarget(G, Target);
auto &GOTEntrySymbol = getGOTEntry(Target);
StubContentBlock.addEdge(x86_64::Delta32, 2, GOTEntrySymbol, -4);
return G.addAnonymousSymbol(StubContentBlock, 0, 6, true, false);
}
void fixPLTEdge(Edge &E, Symbol &Stub) {
assert(E.getKind() == x86_64::BranchPCRel32 && "Not a Branch32 edge?");
// 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(Stub);
}
private:
Section &getStubsSection(LinkGraph &G) {
Section &getGOTSection() const {
if (!GOTSection)
GOTSection = &G.createSection(ELFGOTSectionName, sys::Memory::MF_READ);
return *GOTSection;
}
Section &getStubsSection() const {
if (!StubsSection) {
auto StubsProt = static_cast<sys::Memory::ProtectionFlags>(
sys::Memory::MF_READ | sys::Memory::MF_EXEC);
@ -146,79 +185,26 @@ private:
return *StubsSection;
}
ArrayRef<char> getGOTEntryBlockContent() {
return {reinterpret_cast<const char *>(NullGOTEntryContent),
sizeof(NullGOTEntryContent)};
}
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"; }
bool fixEdgeKind(LinkGraph &G, Block *B, Edge &E) {
if (E.getKind() == x86_64::RequestTLSDescInGOTAndTransformToDelta32) {
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(x86_64::Delta32);
return true;
}
return false;
}
Symbol &createEntry(LinkGraph &G, Symbol &Target) {
// the TLS Info entry's key value will be written by the fixTLVSectionByName
// pass, so create mutable content.
auto &TLSInfoEntry = G.createMutableContentBlock(
getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()), 0, 8,
0);
TLSInfoEntry.addEdge(x86_64::Pointer64, 8, Target, 0);
return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);
}
private:
Section &getTLSInfoSection(LinkGraph &G) {
if (!TLSInfoTable)
TLSInfoTable =
&G.createSection(ELFTLSInfoSectionName, sys::Memory::MF_READ);
return *TLSInfoTable;
}
ArrayRef<char> getTLSInfoEntryContent() const {
return {reinterpret_cast<const char *>(TLSInfoEntryContent),
sizeof(TLSInfoEntryContent)};
}
Section *TLSInfoTable = nullptr;
mutable Section *GOTSection = nullptr;
mutable Section *StubsSection = nullptr;
};
const uint8_t TLSInfoTableManager_ELF_x86_64::TLSInfoEntryContent[16] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 /*data address*/
};
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);
TLSInfoTableManager_ELF_x86_64 TLSInfo;
visitExistingEdges(G, GOT, PLT, TLSInfo);
return Error::success();
}
} // namespace
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 *getELFX86_64RelocName(uint32_t Type) {
switch (Type) {
#define ELF_RELOC(Name, Number) \
@ -511,8 +497,11 @@ void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
else
Config.PrePrunePasses.push_back(markAllSymbolsLive);
// Add an in-place GOT/Stubs/TLSInfoEntry build pass.
Config.PostPrunePasses.push_back(buildTables_ELF_x86_64);
// Add an in-place GOT/Stubs pass.
Config.PostPrunePasses.push_back(PerGraphTLSInfoBuilder_ELF_x86_64::asPass);
Config.PostPrunePasses.push_back(
PerGraphGOTAndPLTStubsBuilder_ELF_x86_64::asPass);
// Resolve any external section start / end symbols.
Config.PostAllocationPasses.push_back(

View File

@ -0,0 +1,78 @@
//===---------------- PerGraphTLSInfoEntryBuilder.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 Thread local storage info entry for each graph.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHTLSINFOENTRYBUILDER_H
#define LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHTLSINFOENTRYBUILDER_H
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "jitlink"
namespace llvm {
namespace jitlink {
template <typename BuilderImplT> class PerGraphTLSInfoEntryBuilder {
public:
PerGraphTLSInfoEntryBuilder(LinkGraph &G) : G(G) {}
static Error asPass(LinkGraph &G) { return BuilderImplT(G).run(); }
Error run() {
LLVM_DEBUG(dbgs() << "Running Per-Graph TLS Info entry builder:\n ");
std::vector<Block *> Worklist(G.blocks().begin(), G.blocks().end());
for (auto *B : Worklist)
for (auto &E : B->edges()) {
if (impl().isTLSEdgeToFix(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().fixTLSEdge(E, getTLSInfoEntry(E.getTarget()));
}
}
return Error::success();
}
protected:
LinkGraph &G;
Symbol &getTLSInfoEntry(Symbol &Target) {
assert(Target.hasName() && "TLS edge cannot point to anonymous target");
auto TLSInfoEntryI = TLSInfoEntries.find(Target.getName());
if (TLSInfoEntryI == TLSInfoEntries.end()) {
auto &TLSInfoEntry = impl().createTLSInfoEntry(Target);
LLVM_DEBUG({
dbgs() << " Created TLS Info entry for " << Target.getName() << ": "
<< TLSInfoEntry << "\n";
});
TLSInfoEntryI =
TLSInfoEntries.insert(std::make_pair(Target.getName(), &TLSInfoEntry))
.first;
}
assert(TLSInfoEntryI != TLSInfoEntries.end() &&
"Could not get TLSInfo symbol");
LLVM_DEBUG({
dbgs() << " Using TLS Info entry" << *TLSInfoEntryI->second << "\n";
});
return *TLSInfoEntryI->second;
}
private:
DenseMap<StringRef, Symbol *> TLSInfoEntries;
BuilderImplT &impl() { return static_cast<BuilderImplT &>(*this); }
};
} // namespace jitlink
} // namespace llvm
#endif

View File

@ -1,75 +0,0 @@
//===---------------------- TableManager.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
//
//===----------------------------------------------------------------------===//
//
// Fix edge for edge that needs an entry to reference the target symbol
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_EXECUTIONENGINE_JITLINK_TABLEMANAGER_H
#define LLVM_EXECUTIONENGINE_JITLINK_TABLEMANAGER_H
#include "llvm/ExecutionEngine/JITLink/JITLink.h"
#include "llvm/Support/Debug.h"
#define DEBUG_TYPE "jitlink"
namespace llvm {
namespace jitlink {
/// Table like section manager
template <typename TableManagerImplT> class TableManager {
public:
/// Visit edge, return true if the edge was dealt with, otherwise return
/// false(let other managers to visit).
bool visitEdge(LinkGraph &G, Block *B, Edge &E) {
if (impl().fixEdgeKind(G, B, E)) {
fixTarget(G, E);
return true;
}
return false;
}
/// Return the constructed entry
///
/// Use parameter G to construct the entry for target symbol
Symbol &getEntryForTarget(LinkGraph &G, Symbol &Target) {
assert(Target.hasName() && "Edge cannot point to anonymous target");
auto EntryI = Entries.find(Target.getName());
// Build the entry if it doesn't exist.
if (EntryI == Entries.end()) {
auto &Entry = impl().createEntry(G, Target);
LLVM_DEBUG({
dbgs() << " Created" << impl().getTableName() << "entry for "
<< Target.getName() << ": " << Entry << "\n";
});
EntryI = Entries.insert(std::make_pair(Target.getName(), &Entry)).first;
}
assert(EntryI != Entries.end() && "Could not get entry symbol");
LLVM_DEBUG({
dbgs() << " Using " << impl().getTableName() << " entry "
<< *EntryI->second << "\n";
});
return *EntryI->second;
}
private:
void fixTarget(LinkGraph &G, Edge &E) {
E.setTarget(getEntryForTarget(G, E.getTarget()));
}
TableManagerImplT &impl() { return static_cast<TableManagerImplT &>(*this); }
DenseMap<StringRef, Symbol *> Entries;
};
} // namespace jitlink
} // namespace llvm
#endif