mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[JITLink][ORC] Enable creation / linking of raw jitlink::LinkGraphs.
Separates link graph creation from linking. This allows raw LinkGraphs to be created and passed to a link. ObjectLinkingLayer is updated to support emission of raw LinkGraphs in addition to object buffers. Raw LinkGraphs can be created by in-memory compilers to bypass object encoding / decoding (though this prevents caching, as LinkGraphs have do not have an on-disk representation), and by utility code to add programatically generated data structures to the JIT target process.
This commit is contained in:
parent
f62c427dbf
commit
36c0911571
@ -19,11 +19,20 @@
|
||||
namespace llvm {
|
||||
namespace jitlink {
|
||||
|
||||
/// jit-link the given ObjBuffer, which must be a ELF object file.
|
||||
/// Create a LinkGraph from an ELF relocatable object.
|
||||
///
|
||||
/// Note: The graph does not take ownership of the underlying buffer, nor copy
|
||||
/// its contents. The caller is responsible for ensuring that the object buffer
|
||||
/// outlives the graph.
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer);
|
||||
|
||||
/// Link the given graph.
|
||||
///
|
||||
/// Uses conservative defaults for GOT and stub handling based on the target
|
||||
/// platform.
|
||||
void jitLink_ELF(std::unique_ptr<JITLinkContext> Ctx);
|
||||
void link_ELF(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx);
|
||||
|
||||
} // end namespace jitlink
|
||||
} // end namespace llvm
|
||||
|
@ -44,8 +44,18 @@ enum ELFX86RelocationKind : Edge::Kind {
|
||||
|
||||
} // end namespace ELF_x86_64_Edges
|
||||
|
||||
/// Create a LinkGraph from an ELF/x86-64 relocatable object.
|
||||
///
|
||||
/// Note: The graph does not take ownership of the underlying buffer, nor copy
|
||||
/// its contents. The caller is responsible for ensuring that the object buffer
|
||||
/// outlives the graph.
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer);
|
||||
|
||||
/// 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);
|
||||
void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx);
|
||||
|
||||
/// Return the string name of the given ELF x86-64 edge kind.
|
||||
StringRef getELFX86RelocationKindName(Edge::Kind R);
|
||||
} // end namespace jitlink
|
||||
|
@ -786,24 +786,40 @@ public:
|
||||
Section::const_block_iterator, const Block *,
|
||||
getSectionConstBlocks>;
|
||||
|
||||
LinkGraph(std::string Name, unsigned PointerSize,
|
||||
LinkGraph(std::string Name, const Triple &TT, unsigned PointerSize,
|
||||
support::endianness Endianness)
|
||||
: Name(std::move(Name)), PointerSize(PointerSize),
|
||||
: Name(std::move(Name)), TT(TT), PointerSize(PointerSize),
|
||||
Endianness(Endianness) {}
|
||||
|
||||
/// Returns the name of this graph (usually the name of the original
|
||||
/// underlying MemoryBuffer).
|
||||
const std::string &getName() { return Name; }
|
||||
|
||||
/// Returns the target triple for this Graph.
|
||||
const Triple &getTargetTriple() const { return TT; }
|
||||
|
||||
/// Returns the pointer size for use in this graph.
|
||||
unsigned getPointerSize() const { return PointerSize; }
|
||||
|
||||
/// Returns the endianness of content in this graph.
|
||||
support::endianness getEndianness() const { return Endianness; }
|
||||
|
||||
/// Allocate a copy of the given String using the LinkGraph's allocator.
|
||||
/// Allocate a copy of the given string using the LinkGraph's allocator.
|
||||
/// This can be useful when renaming symbols or adding new content to the
|
||||
/// graph.
|
||||
StringRef allocateString(StringRef Source) {
|
||||
auto *AllocatedBuffer = Allocator.Allocate<char>(Source.size());
|
||||
llvm::copy(Source, AllocatedBuffer);
|
||||
return StringRef(AllocatedBuffer, Source.size());
|
||||
}
|
||||
|
||||
/// Allocate a copy of the given string using the LinkGraph's allocator.
|
||||
/// This can be useful when renaming symbols or adding new content to the
|
||||
/// graph.
|
||||
///
|
||||
/// Note: This Twine-based overload requires an extra string copy and an
|
||||
/// extra heap allocation for large strings. The StringRef overload should
|
||||
/// be preferred where possible.
|
||||
StringRef allocateString(Twine Source) {
|
||||
SmallString<256> TmpBuffer;
|
||||
auto SourceStr = Source.toStringRef(TmpBuffer);
|
||||
@ -1034,6 +1050,7 @@ private:
|
||||
BumpPtrAllocator Allocator;
|
||||
|
||||
std::string Name;
|
||||
Triple TT;
|
||||
unsigned PointerSize;
|
||||
support::endianness Endianness;
|
||||
SectionList Sections;
|
||||
@ -1282,10 +1299,6 @@ public:
|
||||
/// Return the MemoryManager to be used for this link.
|
||||
virtual JITLinkMemoryManager &getMemoryManager() = 0;
|
||||
|
||||
/// Returns a StringRef for the object buffer.
|
||||
/// This method can not be called once takeObjectBuffer has been called.
|
||||
virtual MemoryBufferRef getObjectBuffer() const = 0;
|
||||
|
||||
/// Notify this context that linking failed.
|
||||
/// Called by JITLink if linking cannot be completed.
|
||||
virtual void notifyFailed(Error Err) = 0;
|
||||
@ -1339,10 +1352,16 @@ private:
|
||||
/// conservative mark-live implementation.
|
||||
Error markAllSymbolsLive(LinkGraph &G);
|
||||
|
||||
/// Basic JITLink implementation.
|
||||
/// Create a LinkGraph from the given object buffer.
|
||||
///
|
||||
/// This function will use sensible defaults for GOT and Stub handling.
|
||||
void jitLink(std::unique_ptr<JITLinkContext> Ctx);
|
||||
/// Note: The graph does not take ownership of the underlying buffer, nor copy
|
||||
/// its contents. The caller is responsible for ensuring that the object buffer
|
||||
/// outlives the graph.
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromObject(MemoryBufferRef ObjectBuffer);
|
||||
|
||||
/// Link the given graph.
|
||||
void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx);
|
||||
|
||||
} // end namespace jitlink
|
||||
} // end namespace llvm
|
||||
|
@ -18,11 +18,20 @@
|
||||
namespace llvm {
|
||||
namespace jitlink {
|
||||
|
||||
/// Create a LinkGraph from a MachO relocatable object.
|
||||
///
|
||||
/// Note: The graph does not take ownership of the underlying buffer, nor copy
|
||||
/// its contents. The caller is responsible for ensuring that the object buffer
|
||||
/// outlives the graph.
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer);
|
||||
|
||||
/// jit-link the given ObjBuffer, which must be a MachO object file.
|
||||
///
|
||||
/// Uses conservative defaults for GOT and stub handling based on the target
|
||||
/// platform.
|
||||
void jitLink_MachO(std::unique_ptr<JITLinkContext> Ctx);
|
||||
void link_MachO(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx);
|
||||
|
||||
} // end namespace jitlink
|
||||
} // end namespace llvm
|
||||
|
@ -40,6 +40,14 @@ enum MachOARM64RelocationKind : Edge::Kind {
|
||||
|
||||
} // namespace MachO_arm64_Edges
|
||||
|
||||
/// Create a LinkGraph from a MachO/arm64 relocatable object.
|
||||
///
|
||||
/// Note: The graph does not take ownership of the underlying buffer, nor copy
|
||||
/// its contents. The caller is responsible for ensuring that the object buffer
|
||||
/// outlives the graph.
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer);
|
||||
|
||||
/// jit-link the given object buffer, which must be a MachO arm64 object file.
|
||||
///
|
||||
/// If PrePrunePasses is empty then a default mark-live pass will be inserted
|
||||
@ -49,7 +57,8 @@ enum MachOARM64RelocationKind : Edge::Kind {
|
||||
/// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
|
||||
/// be inserted. If PostPrunePasses is not empty then the caller is responsible
|
||||
/// for including a pass to insert GOT and stub edges.
|
||||
void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx);
|
||||
void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx);
|
||||
|
||||
/// Return the string name of the given MachO arm64 edge kind.
|
||||
StringRef getMachOARM64RelocationKindName(Edge::Kind R);
|
||||
|
@ -45,7 +45,15 @@ enum MachOX86RelocationKind : Edge::Kind {
|
||||
|
||||
} // namespace MachO_x86_64_Edges
|
||||
|
||||
/// jit-link the given object buffer, which must be a MachO x86-64 object file.
|
||||
/// Create a LinkGraph from a MachO/x86-64 relocatable object.
|
||||
///
|
||||
/// Note: The graph does not take ownership of the underlying buffer, nor copy
|
||||
/// its contents. The caller is responsible for ensuring that the object buffer
|
||||
/// outlives the graph.
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer);
|
||||
|
||||
/// jit-link the given LinkGraph.
|
||||
///
|
||||
/// If PrePrunePasses is empty then a default mark-live pass will be inserted
|
||||
/// that will mark all exported atoms live. If PrePrunePasses is not empty, the
|
||||
@ -54,7 +62,8 @@ enum MachOX86RelocationKind : Edge::Kind {
|
||||
/// If PostPrunePasses is empty then a default GOT-and-stubs insertion pass will
|
||||
/// be inserted. If PostPrunePasses is not empty then the caller is responsible
|
||||
/// for including a pass to insert GOT and stub edges.
|
||||
void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx);
|
||||
void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx);
|
||||
|
||||
/// Return the string name of the given MachO x86-64 edge kind.
|
||||
StringRef getMachOX86RelocationKindName(Edge::Kind R);
|
||||
|
@ -35,6 +35,7 @@ namespace llvm {
|
||||
|
||||
namespace jitlink {
|
||||
class EHFrameRegistrar;
|
||||
class LinkGraph;
|
||||
class Symbol;
|
||||
} // namespace jitlink
|
||||
|
||||
@ -118,10 +119,14 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Emit the object.
|
||||
/// Emit an object file.
|
||||
void emit(std::unique_ptr<MaterializationResponsibility> R,
|
||||
std::unique_ptr<MemoryBuffer> O) override;
|
||||
|
||||
/// Emit a LinkGraph.
|
||||
void emit(std::unique_ptr<MaterializationResponsibility> R,
|
||||
std::unique_ptr<jitlink::LinkGraph> G);
|
||||
|
||||
/// Instructs this ObjectLinkingLayer instance to override the symbol flags
|
||||
/// found in the AtomGraph with the flags supplied by the
|
||||
/// MaterializationResponsibility instance. This is a workaround to support
|
||||
|
@ -50,32 +50,39 @@ Expected<uint16_t> readTargetMachineArch(StringRef Buffer) {
|
||||
return ELF::EM_NONE;
|
||||
}
|
||||
|
||||
void jitLink_ELF(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
StringRef Buffer = Ctx->getObjectBuffer().getBuffer();
|
||||
if (Buffer.size() < ELF::EI_MAG3 + 1) {
|
||||
Ctx->notifyFailed(make_error<JITLinkError>("Truncated ELF buffer"));
|
||||
return;
|
||||
}
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromELFObject(MemoryBufferRef ObjectBuffer) {
|
||||
StringRef Buffer = ObjectBuffer.getBuffer();
|
||||
if (Buffer.size() < ELF::EI_MAG3 + 1)
|
||||
return make_error<JITLinkError>("Truncated ELF buffer");
|
||||
|
||||
if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0) {
|
||||
Ctx->notifyFailed(make_error<JITLinkError>("ELF magic not valid"));
|
||||
return;
|
||||
}
|
||||
if (memcmp(Buffer.data(), ELF::ElfMagic, strlen(ELF::ElfMagic)) != 0)
|
||||
return make_error<JITLinkError>("ELF magic not valid");
|
||||
|
||||
Expected<uint16_t> TargetMachineArch = readTargetMachineArch(Buffer);
|
||||
if (!TargetMachineArch) {
|
||||
Ctx->notifyFailed(TargetMachineArch.takeError());
|
||||
return;
|
||||
}
|
||||
if (!TargetMachineArch)
|
||||
return TargetMachineArch.takeError();
|
||||
|
||||
switch (*TargetMachineArch) {
|
||||
case ELF::EM_X86_64:
|
||||
jitLink_ELF_x86_64(std::move(Ctx));
|
||||
return createLinkGraphFromELFObject_x86_64(std::move(ObjectBuffer));
|
||||
default:
|
||||
return make_error<JITLinkError>(
|
||||
"Unsupported target machine architecture in ELF object " +
|
||||
ObjectBuffer.getBufferIdentifier());
|
||||
}
|
||||
}
|
||||
|
||||
void link_ELF(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx) {
|
||||
switch (G->getTargetTriple().getArch()) {
|
||||
case Triple::x86_64:
|
||||
link_ELF_x86_64(std::move(G), std::move(Ctx));
|
||||
return;
|
||||
default:
|
||||
Ctx->notifyFailed(make_error<JITLinkError>(
|
||||
"Unsupported target machine architecture in ELF object " +
|
||||
Ctx->getObjectBuffer().getBufferIdentifier()));
|
||||
"Unsupported target machine architecture in ELF link graph " +
|
||||
G->getName()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -571,10 +571,11 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
ELFLinkGraphBuilder_x86_64(std::string filename,
|
||||
ELFLinkGraphBuilder_x86_64(StringRef FileName,
|
||||
const object::ELFFile<object::ELF64LE> &Obj)
|
||||
: G(std::make_unique<LinkGraph>(filename, getPointerSize(Obj),
|
||||
getEndianness(Obj))),
|
||||
: G(std::make_unique<LinkGraph>(FileName.str(),
|
||||
Triple("x86_64-unknown-linux"),
|
||||
getPointerSize(Obj), getEndianness(Obj))),
|
||||
Obj(Obj) {}
|
||||
|
||||
Expected<std::unique_ptr<LinkGraph>> buildGraph() {
|
||||
@ -610,27 +611,15 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> {
|
||||
|
||||
public:
|
||||
ELFJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
|
||||
std::unique_ptr<LinkGraph> G,
|
||||
PassConfiguration PassConfig)
|
||||
: JITLinker(std::move(Ctx), std::move(PassConfig)) {}
|
||||
: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
|
||||
|
||||
private:
|
||||
StringRef getEdgeKindName(Edge::Kind R) const override {
|
||||
return getELFX86RelocationKindName(R);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
buildGraph(MemoryBufferRef ObjBuffer) override {
|
||||
auto ELFObj = object::ObjectFile::createELFObjectFile(ObjBuffer);
|
||||
if (!ELFObj)
|
||||
return ELFObj.takeError();
|
||||
|
||||
auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
|
||||
std::string fileName(ELFObj->get()->getFileName());
|
||||
return ELFLinkGraphBuilder_x86_64(std::move(fileName),
|
||||
ELFObjFile.getELFFile())
|
||||
.buildGraph();
|
||||
}
|
||||
|
||||
Error applyFixup(Block &B, const Edge &E, char *BlockWorkingMem) const {
|
||||
using namespace ELF_x86_64_Edges;
|
||||
using namespace llvm::support;
|
||||
@ -655,12 +644,30 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromELFObject_x86_64(MemoryBufferRef ObjectBuffer) {
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Building jitlink graph for new input "
|
||||
<< ObjectBuffer.getBufferIdentifier() << "...\n";
|
||||
});
|
||||
|
||||
auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);
|
||||
if (!ELFObj)
|
||||
return ELFObj.takeError();
|
||||
|
||||
auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF64LE>>(**ELFObj);
|
||||
return ELFLinkGraphBuilder_x86_64((*ELFObj)->getFileName(),
|
||||
ELFObjFile.getELFFile())
|
||||
.buildGraph();
|
||||
}
|
||||
|
||||
void link_ELF_x86_64(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx) {
|
||||
PassConfiguration Config;
|
||||
Triple TT("x86_64-linux");
|
||||
|
||||
// Construct a JITLinker and run the link function.
|
||||
// Add a mark-live pass.
|
||||
if (auto MarkLive = Ctx->getMarkLivePass(TT))
|
||||
if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
|
||||
Config.PrePrunePasses.push_back(std::move(MarkLive));
|
||||
else
|
||||
Config.PrePrunePasses.push_back(markAllSymbolsLive);
|
||||
@ -674,10 +681,10 @@ void jitLink_ELF_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
// Add GOT/Stubs optimizer pass.
|
||||
Config.PostAllocationPasses.push_back(optimizeELF_x86_64_GOTAndStubs);
|
||||
|
||||
if (auto Err = Ctx->modifyPassConfig(TT, Config))
|
||||
if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
|
||||
return Ctx->notifyFailed(std::move(Err));
|
||||
|
||||
ELFJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
|
||||
ELFJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
|
||||
}
|
||||
StringRef getELFX86RelocationKindName(Edge::Kind R) {
|
||||
switch (R) {
|
||||
|
@ -322,15 +322,27 @@ Error markAllSymbolsLive(LinkGraph &G) {
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
void jitLink(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
auto Magic = identify_magic(Ctx->getObjectBuffer().getBuffer());
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromObject(MemoryBufferRef ObjectBuffer) {
|
||||
auto Magic = identify_magic(ObjectBuffer.getBuffer());
|
||||
switch (Magic) {
|
||||
case file_magic::macho_object:
|
||||
return jitLink_MachO(std::move(Ctx));
|
||||
return createLinkGraphFromMachOObject(std::move(ObjectBuffer));
|
||||
case file_magic::elf_relocatable:
|
||||
return jitLink_ELF(std::move(Ctx));
|
||||
return createLinkGraphFromELFObject(std::move(ObjectBuffer));
|
||||
default:
|
||||
Ctx->notifyFailed(make_error<JITLinkError>("Unsupported file format"));
|
||||
return make_error<JITLinkError>("Unsupported file format");
|
||||
};
|
||||
}
|
||||
|
||||
void link(std::unique_ptr<LinkGraph> G, std::unique_ptr<JITLinkContext> Ctx) {
|
||||
switch (G->getTargetTriple().getObjectFormat()) {
|
||||
case Triple::MachO:
|
||||
return link_MachO(std::move(G), std::move(Ctx));
|
||||
case Triple::ELF:
|
||||
return link_ELF(std::move(G), std::move(Ctx));
|
||||
default:
|
||||
Ctx->notifyFailed(make_error<JITLinkError>("Unsupported object format"));
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -24,18 +24,6 @@ JITLinkerBase::~JITLinkerBase() {}
|
||||
|
||||
void JITLinkerBase::linkPhase1(std::unique_ptr<JITLinkerBase> Self) {
|
||||
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Building jitlink graph for new input "
|
||||
<< Ctx->getObjectBuffer().getBufferIdentifier() << "...\n";
|
||||
});
|
||||
|
||||
// Build the link graph.
|
||||
if (auto GraphOrErr = buildGraph(Ctx->getObjectBuffer()))
|
||||
G = std::move(*GraphOrErr);
|
||||
else
|
||||
return Ctx->notifyFailed(GraphOrErr.takeError());
|
||||
assert(G && "Graph should have been created by buildGraph above");
|
||||
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "Starting link phase 1 for graph " << G->getName() << "\n";
|
||||
});
|
||||
|
@ -32,9 +32,11 @@ namespace jitlink {
|
||||
/// remaining linker work) to allow them to be performed asynchronously.
|
||||
class JITLinkerBase {
|
||||
public:
|
||||
JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, PassConfiguration Passes)
|
||||
: Ctx(std::move(Ctx)), Passes(std::move(Passes)) {
|
||||
JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx,
|
||||
std::unique_ptr<LinkGraph> G, PassConfiguration Passes)
|
||||
: Ctx(std::move(Ctx)), G(std::move(G)), Passes(std::move(Passes)) {
|
||||
assert(this->Ctx && "Ctx can not be null");
|
||||
assert(this->G && "G can not be null");
|
||||
}
|
||||
|
||||
virtual ~JITLinkerBase();
|
||||
@ -50,8 +52,7 @@ protected:
|
||||
using SegmentLayoutMap = DenseMap<unsigned, SegmentLayout>;
|
||||
|
||||
// Phase 1:
|
||||
// 1.1: Build link graph
|
||||
// 1.2: Run pre-prune passes
|
||||
// 1.1: Run pre-prune passes
|
||||
// 1.2: Prune graph
|
||||
// 1.3: Run post-prune passes
|
||||
// 1.4: Sort blocks into segments
|
||||
@ -72,11 +73,6 @@ protected:
|
||||
// 3.1: Call OnFinalized callback, handing off allocation.
|
||||
void linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err);
|
||||
|
||||
// Build a graph from the given object buffer.
|
||||
// To be implemented by the client.
|
||||
virtual Expected<std::unique_ptr<LinkGraph>>
|
||||
buildGraph(MemoryBufferRef ObjBuffer) = 0;
|
||||
|
||||
// For debug dumping of the link graph.
|
||||
virtual StringRef getEdgeKindName(Edge::Kind K) const = 0;
|
||||
|
||||
@ -113,8 +109,8 @@ private:
|
||||
void dumpGraph(raw_ostream &OS);
|
||||
|
||||
std::unique_ptr<JITLinkContext> Ctx;
|
||||
PassConfiguration Passes;
|
||||
std::unique_ptr<LinkGraph> G;
|
||||
PassConfiguration Passes;
|
||||
std::unique_ptr<JITLinkMemoryManager::Allocation> Alloc;
|
||||
};
|
||||
|
||||
|
@ -27,39 +27,29 @@ using namespace llvm;
|
||||
namespace llvm {
|
||||
namespace jitlink {
|
||||
|
||||
void jitLink_MachO(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
|
||||
// We don't want to do full MachO validation here. Just parse enough of the
|
||||
// header to find out what MachO linker to use.
|
||||
|
||||
StringRef Data = Ctx->getObjectBuffer().getBuffer();
|
||||
if (Data.size() < 4) {
|
||||
StringRef BufferName = Ctx->getObjectBuffer().getBufferIdentifier();
|
||||
Ctx->notifyFailed(make_error<JITLinkError>("Truncated MachO buffer \"" +
|
||||
BufferName + "\""));
|
||||
return;
|
||||
}
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromMachOObject(MemoryBufferRef ObjectBuffer) {
|
||||
StringRef Data = ObjectBuffer.getBuffer();
|
||||
if (Data.size() < 4)
|
||||
return make_error<JITLinkError>("Truncated MachO buffer \"" +
|
||||
ObjectBuffer.getBufferIdentifier() + "\"");
|
||||
|
||||
uint32_t Magic;
|
||||
memcpy(&Magic, Data.data(), sizeof(uint32_t));
|
||||
LLVM_DEBUG({
|
||||
dbgs() << "jitLink_MachO: magic = " << format("0x%08" PRIx32, Magic)
|
||||
<< ", identifier = \""
|
||||
<< Ctx->getObjectBuffer().getBufferIdentifier() << "\"\n";
|
||||
<< ", identifier = \"" << ObjectBuffer.getBufferIdentifier()
|
||||
<< "\"\n";
|
||||
});
|
||||
|
||||
if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM) {
|
||||
Ctx->notifyFailed(
|
||||
make_error<JITLinkError>("MachO 32-bit platforms not supported"));
|
||||
return;
|
||||
} else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) {
|
||||
if (Magic == MachO::MH_MAGIC || Magic == MachO::MH_CIGAM)
|
||||
return make_error<JITLinkError>("MachO 32-bit platforms not supported");
|
||||
else if (Magic == MachO::MH_MAGIC_64 || Magic == MachO::MH_CIGAM_64) {
|
||||
|
||||
if (Data.size() < sizeof(MachO::mach_header_64)) {
|
||||
StringRef BufferName = Ctx->getObjectBuffer().getBufferIdentifier();
|
||||
Ctx->notifyFailed(make_error<JITLinkError>("Truncated MachO buffer \"" +
|
||||
BufferName + "\""));
|
||||
return;
|
||||
}
|
||||
if (Data.size() < sizeof(MachO::mach_header_64))
|
||||
return make_error<JITLinkError>("Truncated MachO buffer \"" +
|
||||
ObjectBuffer.getBufferIdentifier() +
|
||||
"\"");
|
||||
|
||||
// Read the CPU type from the header.
|
||||
uint32_t CPUType;
|
||||
@ -74,15 +64,27 @@ void jitLink_MachO(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
|
||||
switch (CPUType) {
|
||||
case MachO::CPU_TYPE_ARM64:
|
||||
return jitLink_MachO_arm64(std::move(Ctx));
|
||||
return createLinkGraphFromMachOObject_arm64(std::move(ObjectBuffer));
|
||||
case MachO::CPU_TYPE_X86_64:
|
||||
return jitLink_MachO_x86_64(std::move(Ctx));
|
||||
return createLinkGraphFromMachOObject_x86_64(std::move(ObjectBuffer));
|
||||
}
|
||||
return make_error<JITLinkError>("MachO-64 CPU type not valid");
|
||||
} else
|
||||
return make_error<JITLinkError>("Unrecognized MachO magic value");
|
||||
}
|
||||
|
||||
void link_MachO(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx) {
|
||||
|
||||
switch (G->getTargetTriple().getArch()) {
|
||||
case Triple::aarch64:
|
||||
return link_MachO_arm64(std::move(G), std::move(Ctx));
|
||||
case Triple::x86_64:
|
||||
return link_MachO_x86_64(std::move(G), std::move(Ctx));
|
||||
default:
|
||||
Ctx->notifyFailed(make_error<JITLinkError>("MachO-64 CPU type not valid"));
|
||||
return;
|
||||
}
|
||||
|
||||
Ctx->notifyFailed(make_error<JITLinkError>("MachO magic not valid"));
|
||||
}
|
||||
|
||||
} // end namespace jitlink
|
||||
|
@ -45,10 +45,12 @@ Expected<std::unique_ptr<LinkGraph>> MachOLinkGraphBuilder::buildGraph() {
|
||||
return std::move(G);
|
||||
}
|
||||
|
||||
MachOLinkGraphBuilder::MachOLinkGraphBuilder(const object::MachOObjectFile &Obj)
|
||||
MachOLinkGraphBuilder::MachOLinkGraphBuilder(const object::MachOObjectFile &Obj,
|
||||
Triple TT)
|
||||
: Obj(Obj),
|
||||
G(std::make_unique<LinkGraph>(std::string(Obj.getFileName()),
|
||||
getPointerSize(Obj), getEndianness(Obj))) {}
|
||||
std::move(TT), getPointerSize(Obj),
|
||||
getEndianness(Obj))) {}
|
||||
|
||||
void MachOLinkGraphBuilder::addCustomSectionParser(
|
||||
StringRef SectionName, SectionParserFunction Parser) {
|
||||
|
@ -81,7 +81,7 @@ protected:
|
||||
|
||||
using SectionParserFunction = std::function<Error(NormalizedSection &S)>;
|
||||
|
||||
MachOLinkGraphBuilder(const object::MachOObjectFile &Obj);
|
||||
MachOLinkGraphBuilder(const object::MachOObjectFile &Obj, Triple TT);
|
||||
|
||||
LinkGraph &getGraph() const { return *G; }
|
||||
|
||||
|
@ -26,7 +26,7 @@ namespace {
|
||||
class MachOLinkGraphBuilder_arm64 : public MachOLinkGraphBuilder {
|
||||
public:
|
||||
MachOLinkGraphBuilder_arm64(const object::MachOObjectFile &Obj)
|
||||
: MachOLinkGraphBuilder(Obj),
|
||||
: MachOLinkGraphBuilder(Obj, Triple("arm64-apple-darwin")),
|
||||
NumSymbols(Obj.getSymtabLoadCommand().nsyms) {}
|
||||
|
||||
private:
|
||||
@ -501,22 +501,15 @@ class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> {
|
||||
|
||||
public:
|
||||
MachOJITLinker_arm64(std::unique_ptr<JITLinkContext> Ctx,
|
||||
std::unique_ptr<LinkGraph> G,
|
||||
PassConfiguration PassConfig)
|
||||
: JITLinker(std::move(Ctx), std::move(PassConfig)) {}
|
||||
: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
|
||||
|
||||
private:
|
||||
StringRef getEdgeKindName(Edge::Kind R) const override {
|
||||
return getMachOARM64RelocationKindName(R);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
buildGraph(MemoryBufferRef ObjBuffer) override {
|
||||
auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
|
||||
if (!MachOObj)
|
||||
return MachOObj.takeError();
|
||||
return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
|
||||
}
|
||||
|
||||
static Error targetOutOfRangeError(const Block &B, const Edge &E) {
|
||||
std::string ErrMsg;
|
||||
{
|
||||
@ -681,13 +674,22 @@ private:
|
||||
uint64_t NullValue = 0;
|
||||
};
|
||||
|
||||
void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
PassConfiguration Config;
|
||||
Triple TT("arm64-apple-ios");
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromMachOObject_arm64(MemoryBufferRef ObjectBuffer) {
|
||||
auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
|
||||
if (!MachOObj)
|
||||
return MachOObj.takeError();
|
||||
return MachOLinkGraphBuilder_arm64(**MachOObj).buildGraph();
|
||||
}
|
||||
|
||||
if (Ctx->shouldAddDefaultTargetPasses(TT)) {
|
||||
void link_MachO_arm64(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx) {
|
||||
|
||||
PassConfiguration Config;
|
||||
|
||||
if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
|
||||
// Add a mark-live pass.
|
||||
if (auto MarkLive = Ctx->getMarkLivePass(TT))
|
||||
if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
|
||||
Config.PrePrunePasses.push_back(std::move(MarkLive));
|
||||
else
|
||||
Config.PrePrunePasses.push_back(markAllSymbolsLive);
|
||||
@ -699,11 +701,11 @@ void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
});
|
||||
}
|
||||
|
||||
if (auto Err = Ctx->modifyPassConfig(TT, Config))
|
||||
if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
|
||||
return Ctx->notifyFailed(std::move(Err));
|
||||
|
||||
// Construct a JITLinker and run the link function.
|
||||
MachOJITLinker_arm64::link(std::move(Ctx), std::move(Config));
|
||||
MachOJITLinker_arm64::link(std::move(Ctx), std::move(G), std::move(Config));
|
||||
}
|
||||
|
||||
StringRef getMachOARM64RelocationKindName(Edge::Kind R) {
|
||||
|
@ -26,7 +26,7 @@ namespace {
|
||||
class MachOLinkGraphBuilder_x86_64 : public MachOLinkGraphBuilder {
|
||||
public:
|
||||
MachOLinkGraphBuilder_x86_64(const object::MachOObjectFile &Obj)
|
||||
: MachOLinkGraphBuilder(Obj) {}
|
||||
: MachOLinkGraphBuilder(Obj, Triple("x86_64-apple-darwin")) {}
|
||||
|
||||
private:
|
||||
static Expected<MachOX86RelocationKind>
|
||||
@ -548,22 +548,15 @@ class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> {
|
||||
|
||||
public:
|
||||
MachOJITLinker_x86_64(std::unique_ptr<JITLinkContext> Ctx,
|
||||
std::unique_ptr<LinkGraph> G,
|
||||
PassConfiguration PassConfig)
|
||||
: JITLinker(std::move(Ctx), std::move(PassConfig)) {}
|
||||
: JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {}
|
||||
|
||||
private:
|
||||
StringRef getEdgeKindName(Edge::Kind R) const override {
|
||||
return getMachOX86RelocationKindName(R);
|
||||
}
|
||||
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
buildGraph(MemoryBufferRef ObjBuffer) override {
|
||||
auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjBuffer);
|
||||
if (!MachOObj)
|
||||
return MachOObj.takeError();
|
||||
return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
|
||||
}
|
||||
|
||||
static Error targetOutOfRangeError(const Block &B, const Edge &E) {
|
||||
std::string ErrMsg;
|
||||
{
|
||||
@ -660,18 +653,27 @@ private:
|
||||
uint64_t NullValue = 0;
|
||||
};
|
||||
|
||||
void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
PassConfiguration Config;
|
||||
Triple TT("x86_64-apple-macosx");
|
||||
Expected<std::unique_ptr<LinkGraph>>
|
||||
createLinkGraphFromMachOObject_x86_64(MemoryBufferRef ObjectBuffer) {
|
||||
auto MachOObj = object::ObjectFile::createMachOObjectFile(ObjectBuffer);
|
||||
if (!MachOObj)
|
||||
return MachOObj.takeError();
|
||||
return MachOLinkGraphBuilder_x86_64(**MachOObj).buildGraph();
|
||||
}
|
||||
|
||||
if (Ctx->shouldAddDefaultTargetPasses(TT)) {
|
||||
void link_MachO_x86_64(std::unique_ptr<LinkGraph> G,
|
||||
std::unique_ptr<JITLinkContext> Ctx) {
|
||||
|
||||
PassConfiguration Config;
|
||||
|
||||
if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {
|
||||
// Add eh-frame passses.
|
||||
Config.PrePrunePasses.push_back(EHFrameSplitter("__eh_frame"));
|
||||
Config.PrePrunePasses.push_back(
|
||||
EHFrameEdgeFixer("__eh_frame", NegDelta32, Delta64, Delta64));
|
||||
|
||||
// Add a mark-live pass.
|
||||
if (auto MarkLive = Ctx->getMarkLivePass(TT))
|
||||
if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))
|
||||
Config.PrePrunePasses.push_back(std::move(MarkLive));
|
||||
else
|
||||
Config.PrePrunePasses.push_back(markAllSymbolsLive);
|
||||
@ -686,11 +688,11 @@ void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) {
|
||||
Config.PostAllocationPasses.push_back(optimizeMachO_x86_64_GOTAndStubs);
|
||||
}
|
||||
|
||||
if (auto Err = Ctx->modifyPassConfig(TT, Config))
|
||||
if (auto Err = Ctx->modifyPassConfig(G->getTargetTriple(), Config))
|
||||
return Ctx->notifyFailed(std::move(Err));
|
||||
|
||||
// Construct a JITLinker and run the link function.
|
||||
MachOJITLinker_x86_64::link(std::move(Ctx), std::move(Config));
|
||||
MachOJITLinker_x86_64::link(std::move(Ctx), std::move(G), std::move(Config));
|
||||
}
|
||||
|
||||
StringRef getMachOX86RelocationKindName(Edge::Kind R) {
|
||||
|
@ -34,16 +34,12 @@ public:
|
||||
~ObjectLinkingLayerJITLinkContext() {
|
||||
// If there is an object buffer return function then use it to
|
||||
// return ownership of the buffer.
|
||||
if (Layer.ReturnObjectBuffer)
|
||||
if (Layer.ReturnObjectBuffer && ObjBuffer)
|
||||
Layer.ReturnObjectBuffer(std::move(ObjBuffer));
|
||||
}
|
||||
|
||||
JITLinkMemoryManager &getMemoryManager() override { return Layer.MemMgr; }
|
||||
|
||||
MemoryBufferRef getObjectBuffer() const override {
|
||||
return ObjBuffer->getMemBufferRef();
|
||||
}
|
||||
|
||||
void notifyFailed(Error Err) override {
|
||||
for (auto &P : Layer.Plugins)
|
||||
Err = joinErrors(std::move(Err), P->notifyFailed(*MR));
|
||||
@ -463,8 +459,19 @@ ObjectLinkingLayer::~ObjectLinkingLayer() {
|
||||
void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
|
||||
std::unique_ptr<MemoryBuffer> O) {
|
||||
assert(O && "Object must not be null");
|
||||
jitLink(std::make_unique<ObjectLinkingLayerJITLinkContext>(
|
||||
*this, std::move(R), std::move(O)));
|
||||
auto ObjBuffer = O->getMemBufferRef();
|
||||
auto Ctx = std::make_unique<ObjectLinkingLayerJITLinkContext>(
|
||||
*this, std::move(R), std::move(O));
|
||||
if (auto G = createLinkGraphFromObject(std::move(ObjBuffer)))
|
||||
link(std::move(*G), std::move(Ctx));
|
||||
else
|
||||
Ctx->notifyFailed(G.takeError());
|
||||
}
|
||||
|
||||
void ObjectLinkingLayer::emit(std::unique_ptr<MaterializationResponsibility> R,
|
||||
std::unique_ptr<LinkGraph> G) {
|
||||
link(std::move(G), std::make_unique<ObjectLinkingLayerJITLinkContext>(
|
||||
*this, std::move(R), nullptr));
|
||||
}
|
||||
|
||||
void ObjectLinkingLayer::modifyPassConfig(MaterializationResponsibility &MR,
|
||||
|
@ -20,8 +20,9 @@ static auto RWFlags =
|
||||
|
||||
TEST(LinkGraphTest, Construction) {
|
||||
// Check that LinkGraph construction works as expected.
|
||||
LinkGraph G("foo", 8, support::little);
|
||||
LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little);
|
||||
EXPECT_EQ(G.getName(), "foo");
|
||||
EXPECT_EQ(G.getTargetTriple().str(), "x86_64-apple-darwin");
|
||||
EXPECT_EQ(G.getPointerSize(), 8U);
|
||||
EXPECT_EQ(G.getEndianness(), support::little);
|
||||
EXPECT_TRUE(llvm::empty(G.external_symbols()));
|
||||
@ -38,7 +39,7 @@ TEST(LinkGraphTest, BlockAndSymbolIteration) {
|
||||
0x1C, 0x1D, 0x1E, 0x1F, 0x00};
|
||||
StringRef BlockContent(BlockContentBytes);
|
||||
|
||||
LinkGraph G("foo", 8, support::little);
|
||||
LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little);
|
||||
auto &Sec1 = G.createSection("__data.1", RWFlags);
|
||||
auto &B1 = G.createContentBlock(Sec1, BlockContent, 0x1000, 8, 0);
|
||||
auto &B2 = G.createContentBlock(Sec1, BlockContent, 0x2000, 8, 0);
|
||||
@ -90,7 +91,7 @@ TEST(LinkGraphTest, SplitBlock) {
|
||||
0x1C, 0x1D, 0x1E, 0x1F, 0x00};
|
||||
StringRef BlockContent(BlockContentBytes);
|
||||
|
||||
LinkGraph G("foo", 8, support::little);
|
||||
LinkGraph G("foo", Triple("x86_64-apple-darwin"), 8, support::little);
|
||||
auto &Sec = G.createSection("__data", RWFlags);
|
||||
|
||||
// Create the block to split.
|
||||
|
Loading…
Reference in New Issue
Block a user