10b57cec5SDimitry Andric //===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 140b57cec5SDimitry Andric #define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 150b57cec5SDimitry Andric 160b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h" 170b57cec5SDimitry Andric 180b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric namespace llvm { 210b57cec5SDimitry Andric namespace jitlink { 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric /// Base class for a JIT linker. 240b57cec5SDimitry Andric /// 250b57cec5SDimitry Andric /// A JITLinkerBase instance links one object file into an ongoing JIT 260b57cec5SDimitry Andric /// session. Symbol resolution and finalization operations are pluggable, 270b57cec5SDimitry Andric /// and called using continuation passing (passing a continuation for the 280b57cec5SDimitry Andric /// remaining linker work) to allow them to be performed asynchronously. 290b57cec5SDimitry Andric class JITLinkerBase { 300b57cec5SDimitry Andric public: 31e8d8bef9SDimitry Andric JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, 32e8d8bef9SDimitry Andric std::unique_ptr<LinkGraph> G, PassConfiguration Passes) 33e8d8bef9SDimitry Andric : Ctx(std::move(Ctx)), G(std::move(G)), Passes(std::move(Passes)) { 340b57cec5SDimitry Andric assert(this->Ctx && "Ctx can not be null"); 35e8d8bef9SDimitry Andric assert(this->G && "G can not be null"); 360b57cec5SDimitry Andric } 370b57cec5SDimitry Andric 380b57cec5SDimitry Andric virtual ~JITLinkerBase(); 390b57cec5SDimitry Andric 400b57cec5SDimitry Andric protected: 41349cc55cSDimitry Andric using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc; 42349cc55cSDimitry Andric using AllocResult = Expected<std::unique_ptr<InFlightAlloc>>; 43349cc55cSDimitry Andric using FinalizeResult = Expected<JITLinkMemoryManager::FinalizedAlloc>; 440b57cec5SDimitry Andric 45*5f757f3fSDimitry Andric // Returns a reference to the graph being linked. 46*5f757f3fSDimitry Andric LinkGraph &getGraph() { return *G; } 47*5f757f3fSDimitry Andric 48*5f757f3fSDimitry Andric // Returns true if the context says that the linker should add default 49*5f757f3fSDimitry Andric // passes. This can be used by JITLinkerBase implementations when deciding 50*5f757f3fSDimitry Andric // whether they should add default passes. 51*5f757f3fSDimitry Andric bool shouldAddDefaultTargetPasses(const Triple &TT) { 52*5f757f3fSDimitry Andric return Ctx->shouldAddDefaultTargetPasses(TT); 53*5f757f3fSDimitry Andric } 54*5f757f3fSDimitry Andric 55fe6060f1SDimitry Andric // Returns the PassConfiguration for this instance. This can be used by 56fe6060f1SDimitry Andric // JITLinkerBase implementations to add late passes that reference their 57fe6060f1SDimitry Andric // own data structures (e.g. for ELF implementations to locate / construct 58fe6060f1SDimitry Andric // a GOT start symbol prior to fixup). 59fe6060f1SDimitry Andric PassConfiguration &getPassConfig() { return Passes; } 60fe6060f1SDimitry Andric 610b57cec5SDimitry Andric // Phase 1: 62e8d8bef9SDimitry Andric // 1.1: Run pre-prune passes 630b57cec5SDimitry Andric // 1.2: Prune graph 640b57cec5SDimitry Andric // 1.3: Run post-prune passes 65349cc55cSDimitry Andric // 1.4: Allocate memory. 660b57cec5SDimitry Andric void linkPhase1(std::unique_ptr<JITLinkerBase> Self); 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric // Phase 2: 69349cc55cSDimitry Andric // 2.2: Run post-allocation passes 70349cc55cSDimitry Andric // 2.3: Notify context of final assigned symbol addresses 71349cc55cSDimitry Andric // 2.4: Identify external symbols and make an async call to resolve 72349cc55cSDimitry Andric void linkPhase2(std::unique_ptr<JITLinkerBase> Self, AllocResult AR); 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric // Phase 3: 75349cc55cSDimitry Andric // 3.1: Apply resolution results 76349cc55cSDimitry Andric // 3.2: Run pre-fixup passes 77349cc55cSDimitry Andric // 3.3: Fix up block contents 78349cc55cSDimitry Andric // 3.4: Run post-fixup passes 79349cc55cSDimitry Andric // 3.5: Make an async call to transfer and finalize memory. 80349cc55cSDimitry Andric void linkPhase3(std::unique_ptr<JITLinkerBase> Self, 81349cc55cSDimitry Andric Expected<AsyncLookupResult> LookupResult); 820b57cec5SDimitry Andric 83349cc55cSDimitry Andric // Phase 4: 84349cc55cSDimitry Andric // 4.1: Call OnFinalized callback, handing off allocation. 85349cc55cSDimitry Andric void linkPhase4(std::unique_ptr<JITLinkerBase> Self, FinalizeResult FR); 868bcb0991SDimitry Andric 870b57cec5SDimitry Andric private: 880b57cec5SDimitry Andric // Run all passes in the given pass list, bailing out immediately if any pass 890b57cec5SDimitry Andric // returns an error. 908bcb0991SDimitry Andric Error runPasses(LinkGraphPassList &Passes); 910b57cec5SDimitry Andric 928bcb0991SDimitry Andric // Copy block contents and apply relocations. 930b57cec5SDimitry Andric // Implemented in JITLinker. 945ffd83dbSDimitry Andric virtual Error fixUpBlocks(LinkGraph &G) const = 0; 950b57cec5SDimitry Andric 96480093f4SDimitry Andric JITLinkContext::LookupMap getExternalSymbolNames() const; 970b57cec5SDimitry Andric void applyLookupResult(AsyncLookupResult LR); 98349cc55cSDimitry Andric void abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self, Error Err); 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric std::unique_ptr<JITLinkContext> Ctx; 1018bcb0991SDimitry Andric std::unique_ptr<LinkGraph> G; 102e8d8bef9SDimitry Andric PassConfiguration Passes; 103349cc55cSDimitry Andric std::unique_ptr<InFlightAlloc> Alloc; 1040b57cec5SDimitry Andric }; 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric template <typename LinkerImpl> class JITLinker : public JITLinkerBase { 1070b57cec5SDimitry Andric public: 1080b57cec5SDimitry Andric using JITLinkerBase::JITLinkerBase; 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric /// Link constructs a LinkerImpl instance and calls linkPhase1. 1110b57cec5SDimitry Andric /// Link should be called with the constructor arguments for LinkerImpl, which 1120b57cec5SDimitry Andric /// will be forwarded to the constructor. 1130b57cec5SDimitry Andric template <typename... ArgTs> static void link(ArgTs &&... Args) { 1148bcb0991SDimitry Andric auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...); 1150b57cec5SDimitry Andric 1160b57cec5SDimitry Andric // Ownership of the linker is passed into the linker's doLink function to 1170b57cec5SDimitry Andric // allow it to be passed on to async continuations. 1180b57cec5SDimitry Andric // 1190b57cec5SDimitry Andric // FIXME: Remove LTmp once we have c++17. 1200b57cec5SDimitry Andric // C++17 sequencing rules guarantee that function name expressions are 1210b57cec5SDimitry Andric // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be 1220b57cec5SDimitry Andric // well formed. 1230b57cec5SDimitry Andric auto <mp = *L; 1240b57cec5SDimitry Andric LTmp.linkPhase1(std::move(L)); 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric private: 1280b57cec5SDimitry Andric const LinkerImpl &impl() const { 1290b57cec5SDimitry Andric return static_cast<const LinkerImpl &>(*this); 1300b57cec5SDimitry Andric } 1310b57cec5SDimitry Andric 1325ffd83dbSDimitry Andric Error fixUpBlocks(LinkGraph &G) const override { 1335ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Fixing up blocks:\n"); 1340b57cec5SDimitry Andric 13506c3fb27SDimitry Andric for (auto &Sec : G.sections()) { 136*5f757f3fSDimitry Andric bool NoAllocSection = Sec.getMemLifetime() == orc::MemLifetime::NoAlloc; 13706c3fb27SDimitry Andric 13806c3fb27SDimitry Andric for (auto *B : Sec.blocks()) { 1398bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << " " << *B << ":\n"); 1400b57cec5SDimitry Andric 1418bcb0991SDimitry Andric // Copy Block data and apply fixups. 1420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Applying fixups.\n"); 143bdd1243dSDimitry Andric assert((!B->isZeroFill() || all_of(B->edges(), 144bdd1243dSDimitry Andric [](const Edge &E) { 145bdd1243dSDimitry Andric return E.getKind() == 146bdd1243dSDimitry Andric Edge::KeepAlive; 147bdd1243dSDimitry Andric })) && 148bdd1243dSDimitry Andric "Non-KeepAlive edges in zero-fill block?"); 14906c3fb27SDimitry Andric 15006c3fb27SDimitry Andric // If this is a no-alloc section then copy the block content into 15106c3fb27SDimitry Andric // memory allocated on the Graph's allocator (if it hasn't been 15206c3fb27SDimitry Andric // already). 15306c3fb27SDimitry Andric if (NoAllocSection) 15406c3fb27SDimitry Andric (void)B->getMutableContent(G); 15506c3fb27SDimitry Andric 1568bcb0991SDimitry Andric for (auto &E : B->edges()) { 1570b57cec5SDimitry Andric 1580b57cec5SDimitry Andric // Skip non-relocation edges. 1590b57cec5SDimitry Andric if (!E.isRelocation()) 1600b57cec5SDimitry Andric continue; 1610b57cec5SDimitry Andric 16206c3fb27SDimitry Andric // If B is a block in a Standard or Finalize section then make sure 16306c3fb27SDimitry Andric // that no edges point to symbols in NoAlloc sections. 164*5f757f3fSDimitry Andric assert((NoAllocSection || !E.getTarget().isDefined() || 165*5f757f3fSDimitry Andric E.getTarget().getBlock().getSection().getMemLifetime() != 166*5f757f3fSDimitry Andric orc::MemLifetime::NoAlloc) && 16706c3fb27SDimitry Andric "Block in allocated section has edge pointing to no-alloc " 16806c3fb27SDimitry Andric "section"); 16906c3fb27SDimitry Andric 1700b57cec5SDimitry Andric // Dispatch to LinkerImpl for fixup. 171fe6060f1SDimitry Andric if (auto Err = impl().applyFixup(G, *B, E)) 1720b57cec5SDimitry Andric return Err; 1730b57cec5SDimitry Andric } 1740b57cec5SDimitry Andric } 17506c3fb27SDimitry Andric } 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric return Error::success(); 1780b57cec5SDimitry Andric } 1790b57cec5SDimitry Andric }; 1800b57cec5SDimitry Andric 1818bcb0991SDimitry Andric /// Removes dead symbols/blocks/addressables. 1820b57cec5SDimitry Andric /// 1838bcb0991SDimitry Andric /// Finds the set of symbols and addressables reachable from any symbol 1848bcb0991SDimitry Andric /// initially marked live. All symbols/addressables not marked live at the end 1858bcb0991SDimitry Andric /// of this process are removed. 1868bcb0991SDimitry Andric void prune(LinkGraph &G); 1870b57cec5SDimitry Andric 1880b57cec5SDimitry Andric } // end namespace jitlink 1890b57cec5SDimitry Andric } // end namespace llvm 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric #undef DEBUG_TYPE // "jitlink" 1920b57cec5SDimitry Andric 19304eeddc0SDimitry Andric #endif // LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 194