Author: Lang Hames Date: 2020-12-16T14:01:50+11:00 New Revision: ec6b71df70a09681cc0ae87945db9f71649cf188
URL: https://github.com/llvm/llvm-project/commit/ec6b71df70a09681cc0ae87945db9f71649cf188 DIFF: https://github.com/llvm/llvm-project/commit/ec6b71df70a09681cc0ae87945db9f71649cf188.diff LOG: [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. Added: Modified: llvm/include/llvm/ExecutionEngine/JITLink/ELF.h llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h llvm/include/llvm/ExecutionEngine/JITLink/MachO.h llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h llvm/lib/ExecutionEngine/JITLink/ELF.cpp llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp llvm/lib/ExecutionEngine/JITLink/JITLink.cpp llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h llvm/lib/ExecutionEngine/JITLink/MachO.cpp llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp Removed: ################################################################################ diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF.h index 9f6ea5271f4b..8912f3a2db45 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/ELF.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF.h @@ -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 diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h index 1e1e282a8997..1423b0c30b2a 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/ELF_x86_64.h @@ -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 diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h index 48e64335613b..6de0cd589aad 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/JITLink.h @@ -786,24 +786,40 @@ class LinkGraph { 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 @@ class LinkGraph { BumpPtrAllocator Allocator; std::string Name; + Triple TT; unsigned PointerSize; support::endianness Endianness; SectionList Sections; @@ -1282,10 +1299,6 @@ class JITLinkContext { /// 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 @@ class JITLinkContext { /// 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 diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/MachO.h b/llvm/include/llvm/ExecutionEngine/JITLink/MachO.h index 7facb657a51c..b8432c4d26c6 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/MachO.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/MachO.h @@ -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 diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h index d70b545fff86..c6aed2b60eac 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_arm64.h @@ -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); diff --git a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h index 27fcdf4fa990..66c53d8c8291 100644 --- a/llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h +++ b/llvm/include/llvm/ExecutionEngine/JITLink/MachO_x86_64.h @@ -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); diff --git a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h index b73217f09b54..f2975e29fcd6 100644 --- a/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h +++ b/llvm/include/llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h @@ -35,6 +35,7 @@ namespace llvm { namespace jitlink { class EHFrameRegistrar; +class LinkGraph; class Symbol; } // namespace jitlink @@ -118,10 +119,14 @@ class ObjectLinkingLayer : public ObjectLayer, private ResourceManager { 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 diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp index 19b878257709..27eb7d576e2d 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF.cpp @@ -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; } } diff --git a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp index 20504b861155..ea05b6c7e638 100644 --- a/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/ELF_x86_64.cpp @@ -571,10 +571,11 @@ class ELFLinkGraphBuilder_x86_64 { } 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 @@ class ELFJITLinker_x86_64 : public JITLinker<ELFJITLinker_x86_64> { } }; -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) { diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp index 71ec88639a5b..41b5423dc335 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLink.cpp @@ -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")); }; } diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp index 393ed0ea7093..f29f6592e6ff 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.cpp @@ -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"; }); diff --git a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h index 87e5e8bbc98d..1d28f5006b2b 100644 --- a/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h +++ b/llvm/lib/ExecutionEngine/JITLink/JITLinkGeneric.h @@ -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 @@ class JITLinkerBase { 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 @@ class JITLinkerBase { // 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 @@ class JITLinkerBase { 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; }; diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO.cpp index b3e45868ab22..e9327df6da41 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO.cpp @@ -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 diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp index cf1bb23da665..4602154eb579 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.cpp @@ -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) { diff --git a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h index dd3bcf27494c..3555d66ace35 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h +++ b/llvm/lib/ExecutionEngine/JITLink/MachOLinkGraphBuilder.h @@ -81,7 +81,7 @@ class MachOLinkGraphBuilder { using SectionParserFunction = std::function<Error(NormalizedSection &S)>; - MachOLinkGraphBuilder(const object::MachOObjectFile &Obj); + MachOLinkGraphBuilder(const object::MachOObjectFile &Obj, Triple TT); LinkGraph &getGraph() const { return *G; } diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp index a7178aa1e450..8366e9658539 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_arm64.cpp @@ -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 @@ class MachOJITLinker_arm64 : public JITLinker<MachOJITLinker_arm64> { uint64_t NullValue = 0; }; -void jitLink_MachO_arm64(std::unique_ptr<JITLinkContext> Ctx) { +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(); +} + +void link_MachO_arm64(std::unique_ptr<LinkGraph> G, + std::unique_ptr<JITLinkContext> Ctx) { + PassConfiguration Config; - Triple TT("arm64-apple-ios"); - if (Ctx->shouldAddDefaultTargetPasses(TT)) { + 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) { diff --git a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp index a70b0dcd8f85..34e0c3250495 100644 --- a/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp +++ b/llvm/lib/ExecutionEngine/JITLink/MachO_x86_64.cpp @@ -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 @@ class MachOJITLinker_x86_64 : public JITLinker<MachOJITLinker_x86_64> { uint64_t NullValue = 0; }; -void jitLink_MachO_x86_64(std::unique_ptr<JITLinkContext> Ctx) { +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(); +} + +void link_MachO_x86_64(std::unique_ptr<LinkGraph> G, + std::unique_ptr<JITLinkContext> Ctx) { + PassConfiguration Config; - Triple TT("x86_64-apple-macosx"); - if (Ctx->shouldAddDefaultTargetPasses(TT)) { + 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) { diff --git a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp index f8eb1dcfce41..161a30e44616 100644 --- a/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp +++ b/llvm/lib/ExecutionEngine/Orc/ObjectLinkingLayer.cpp @@ -34,16 +34,12 @@ class ObjectLinkingLayerJITLinkContext final : public JITLinkContext { ~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, diff --git a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp index 0c2d1b63ad4d..360bc8811f1e 100644 --- a/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp +++ b/llvm/unittests/ExecutionEngine/JITLink/LinkGraphTests.cpp @@ -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. _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits