111c8dfa5SLang Hames //===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===// 211c8dfa5SLang Hames // 311c8dfa5SLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 411c8dfa5SLang Hames // See https://llvm.org/LICENSE.txt for license information. 511c8dfa5SLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 611c8dfa5SLang Hames // 711c8dfa5SLang Hames //===----------------------------------------------------------------------===// 811c8dfa5SLang Hames // 911c8dfa5SLang Hames // Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing. 1011c8dfa5SLang Hames // 1111c8dfa5SLang Hames //===----------------------------------------------------------------------===// 1211c8dfa5SLang Hames 1311c8dfa5SLang Hames #ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 1411c8dfa5SLang Hames #define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 1511c8dfa5SLang Hames 1611c8dfa5SLang Hames #include "llvm/ExecutionEngine/JITLink/JITLink.h" 1711c8dfa5SLang Hames 1811c8dfa5SLang Hames #define DEBUG_TYPE "jitlink" 1911c8dfa5SLang Hames 2011c8dfa5SLang Hames namespace llvm { 2111c8dfa5SLang Hames namespace jitlink { 2211c8dfa5SLang Hames 2311c8dfa5SLang Hames /// Base class for a JIT linker. 2411c8dfa5SLang Hames /// 2511c8dfa5SLang Hames /// A JITLinkerBase instance links one object file into an ongoing JIT 2611c8dfa5SLang Hames /// session. Symbol resolution and finalization operations are pluggable, 2711c8dfa5SLang Hames /// and called using continuation passing (passing a continuation for the 2811c8dfa5SLang Hames /// remaining linker work) to allow them to be performed asynchronously. 2911c8dfa5SLang Hames class JITLinkerBase { 3011c8dfa5SLang Hames public: JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration Passes)31ec6b71dfSLang Hames JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, 32ec6b71dfSLang Hames std::unique_ptr<LinkGraph> G, PassConfiguration Passes) 33ec6b71dfSLang Hames : Ctx(std::move(Ctx)), G(std::move(G)), Passes(std::move(Passes)) { 3411c8dfa5SLang Hames assert(this->Ctx && "Ctx can not be null"); 35ec6b71dfSLang Hames assert(this->G && "G can not be null"); 3611c8dfa5SLang Hames } 3711c8dfa5SLang Hames 3811c8dfa5SLang Hames virtual ~JITLinkerBase(); 3911c8dfa5SLang Hames 4011c8dfa5SLang Hames protected: 41962a2479SLang Hames using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc; 42962a2479SLang Hames using AllocResult = Expected<std::unique_ptr<InFlightAlloc>>; 43962a2479SLang Hames using FinalizeResult = Expected<JITLinkMemoryManager::FinalizedAlloc>; 4411c8dfa5SLang Hames 4535c9072cSLang Hames // Returns a reference to the graph being linked. getGraph()4635c9072cSLang Hames LinkGraph &getGraph() { return *G; } 4735c9072cSLang Hames 48265d6bdaSLang Hames // Returns true if the context says that the linker should add default 49265d6bdaSLang Hames // passes. This can be used by JITLinkerBase implementations when deciding 50265d6bdaSLang Hames // whether they should add default passes. shouldAddDefaultTargetPasses(const Triple & TT)51265d6bdaSLang Hames bool shouldAddDefaultTargetPasses(const Triple &TT) { 52265d6bdaSLang Hames return Ctx->shouldAddDefaultTargetPasses(TT); 53265d6bdaSLang Hames } 54265d6bdaSLang Hames 55fc36a511SLang Hames // Returns the PassConfiguration for this instance. This can be used by 56fc36a511SLang Hames // JITLinkerBase implementations to add late passes that reference their 57fc36a511SLang Hames // own data structures (e.g. for ELF implementations to locate / construct 58fc36a511SLang Hames // a GOT start symbol prior to fixup). getPassConfig()59fc36a511SLang Hames PassConfiguration &getPassConfig() { return Passes; } 60fc36a511SLang Hames 6111c8dfa5SLang Hames // Phase 1: 62ec6b71dfSLang Hames // 1.1: Run pre-prune passes 6311c8dfa5SLang Hames // 1.2: Prune graph 6411c8dfa5SLang Hames // 1.3: Run post-prune passes 65962a2479SLang Hames // 1.4: Allocate memory. 6611c8dfa5SLang Hames void linkPhase1(std::unique_ptr<JITLinkerBase> Self); 6711c8dfa5SLang Hames 6811c8dfa5SLang Hames // Phase 2: 69962a2479SLang Hames // 2.2: Run post-allocation passes 70962a2479SLang Hames // 2.3: Notify context of final assigned symbol addresses 71962a2479SLang Hames // 2.4: Identify external symbols and make an async call to resolve 72962a2479SLang Hames void linkPhase2(std::unique_ptr<JITLinkerBase> Self, AllocResult AR); 7311c8dfa5SLang Hames 7411c8dfa5SLang Hames // Phase 3: 75962a2479SLang Hames // 3.1: Apply resolution results 76962a2479SLang Hames // 3.2: Run pre-fixup passes 77962a2479SLang Hames // 3.3: Fix up block contents 78962a2479SLang Hames // 3.4: Run post-fixup passes 79962a2479SLang Hames // 3.5: Make an async call to transfer and finalize memory. 80962a2479SLang Hames void linkPhase3(std::unique_ptr<JITLinkerBase> Self, 81962a2479SLang Hames Expected<AsyncLookupResult> LookupResult); 8211c8dfa5SLang Hames 83962a2479SLang Hames // Phase 4: 84962a2479SLang Hames // 4.1: Call OnFinalized callback, handing off allocation. 85962a2479SLang Hames void linkPhase4(std::unique_ptr<JITLinkerBase> Self, FinalizeResult FR); 864e920e58SLang Hames 8711c8dfa5SLang Hames private: 8811c8dfa5SLang Hames // Run all passes in the given pass list, bailing out immediately if any pass 8911c8dfa5SLang Hames // returns an error. 904e920e58SLang Hames Error runPasses(LinkGraphPassList &Passes); 9111c8dfa5SLang Hames 924e920e58SLang Hames // Copy block contents and apply relocations. 9311c8dfa5SLang Hames // Implemented in JITLinker. 9427a79b72SLang Hames virtual Error fixUpBlocks(LinkGraph &G) const = 0; 9511c8dfa5SLang Hames 96674df13bSLang Hames JITLinkContext::LookupMap getExternalSymbolNames() const; 9711c8dfa5SLang Hames void applyLookupResult(AsyncLookupResult LR); 98962a2479SLang Hames void abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self, Error Err); 9911c8dfa5SLang Hames 10011c8dfa5SLang Hames std::unique_ptr<JITLinkContext> Ctx; 1014e920e58SLang Hames std::unique_ptr<LinkGraph> G; 102ec6b71dfSLang Hames PassConfiguration Passes; 103962a2479SLang Hames std::unique_ptr<InFlightAlloc> Alloc; 10411c8dfa5SLang Hames }; 10511c8dfa5SLang Hames 10611c8dfa5SLang Hames template <typename LinkerImpl> class JITLinker : public JITLinkerBase { 10711c8dfa5SLang Hames public: 10811c8dfa5SLang Hames using JITLinkerBase::JITLinkerBase; 10911c8dfa5SLang Hames 11011c8dfa5SLang Hames /// Link constructs a LinkerImpl instance and calls linkPhase1. 11111c8dfa5SLang Hames /// Link should be called with the constructor arguments for LinkerImpl, which 11211c8dfa5SLang Hames /// will be forwarded to the constructor. link(ArgTs &&...Args)11311c8dfa5SLang Hames template <typename... ArgTs> static void link(ArgTs &&... Args) { 1140eaee545SJonas Devlieghere auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...); 11511c8dfa5SLang Hames 11611c8dfa5SLang Hames // Ownership of the linker is passed into the linker's doLink function to 11711c8dfa5SLang Hames // allow it to be passed on to async continuations. 11811c8dfa5SLang Hames // 11911c8dfa5SLang Hames // FIXME: Remove LTmp once we have c++17. 12011c8dfa5SLang Hames // C++17 sequencing rules guarantee that function name expressions are 12111c8dfa5SLang Hames // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be 12211c8dfa5SLang Hames // well formed. 12311c8dfa5SLang Hames auto <mp = *L; 12411c8dfa5SLang Hames LTmp.linkPhase1(std::move(L)); 12511c8dfa5SLang Hames } 12611c8dfa5SLang Hames 12711c8dfa5SLang Hames private: impl()12811c8dfa5SLang Hames const LinkerImpl &impl() const { 12911c8dfa5SLang Hames return static_cast<const LinkerImpl &>(*this); 13011c8dfa5SLang Hames } 13111c8dfa5SLang Hames fixUpBlocks(LinkGraph & G)13227a79b72SLang Hames Error fixUpBlocks(LinkGraph &G) const override { 13327a79b72SLang Hames LLVM_DEBUG(dbgs() << "Fixing up blocks:\n"); 13411c8dfa5SLang Hames 1350b7e16afSLang Hames for (auto &Sec : G.sections()) { 136*e994f84cSLang Hames bool NoAllocSection = Sec.getMemLifetime() == orc::MemLifetime::NoAlloc; 1370b7e16afSLang Hames 1380b7e16afSLang Hames for (auto *B : Sec.blocks()) { 1394e920e58SLang Hames LLVM_DEBUG(dbgs() << " " << *B << ":\n"); 14045139290SLang Hames 1414e920e58SLang Hames // Copy Block data and apply fixups. 14211c8dfa5SLang Hames LLVM_DEBUG(dbgs() << " Applying fixups.\n"); 143e7814511SSunho Kim assert((!B->isZeroFill() || all_of(B->edges(), 144e7814511SSunho Kim [](const Edge &E) { 145e7814511SSunho Kim return E.getKind() == 146e7814511SSunho Kim Edge::KeepAlive; 147e7814511SSunho Kim })) && 148e7814511SSunho Kim "Non-KeepAlive edges in zero-fill block?"); 1490b7e16afSLang Hames 1500b7e16afSLang Hames // If this is a no-alloc section then copy the block content into 1510b7e16afSLang Hames // memory allocated on the Graph's allocator (if it hasn't been 1520b7e16afSLang Hames // already). 1530b7e16afSLang Hames if (NoAllocSection) 1540b7e16afSLang Hames (void)B->getMutableContent(G); 1550b7e16afSLang Hames 1564e920e58SLang Hames for (auto &E : B->edges()) { 15711c8dfa5SLang Hames 15811c8dfa5SLang Hames // Skip non-relocation edges. 15911c8dfa5SLang Hames if (!E.isRelocation()) 16011c8dfa5SLang Hames continue; 16111c8dfa5SLang Hames 1620b7e16afSLang Hames // If B is a block in a Standard or Finalize section then make sure 1630b7e16afSLang Hames // that no edges point to symbols in NoAlloc sections. 164*e994f84cSLang Hames assert((NoAllocSection || !E.getTarget().isDefined() || 165*e994f84cSLang Hames E.getTarget().getBlock().getSection().getMemLifetime() != 166*e994f84cSLang Hames orc::MemLifetime::NoAlloc) && 1670b7e16afSLang Hames "Block in allocated section has edge pointing to no-alloc " 1680b7e16afSLang Hames "section"); 1690b7e16afSLang Hames 17011c8dfa5SLang Hames // Dispatch to LinkerImpl for fixup. 17182ad2b6eSLang Hames if (auto Err = impl().applyFixup(G, *B, E)) 17211c8dfa5SLang Hames return Err; 17311c8dfa5SLang Hames } 17411c8dfa5SLang Hames } 1750b7e16afSLang Hames } 17611c8dfa5SLang Hames 17711c8dfa5SLang Hames return Error::success(); 17811c8dfa5SLang Hames } 17911c8dfa5SLang Hames }; 18011c8dfa5SLang Hames 1814e920e58SLang Hames /// Removes dead symbols/blocks/addressables. 18211c8dfa5SLang Hames /// 1834e920e58SLang Hames /// Finds the set of symbols and addressables reachable from any symbol 1844e920e58SLang Hames /// initially marked live. All symbols/addressables not marked live at the end 1854e920e58SLang Hames /// of this process are removed. 1864e920e58SLang Hames void prune(LinkGraph &G); 18711c8dfa5SLang Hames 18811c8dfa5SLang Hames } // end namespace jitlink 18911c8dfa5SLang Hames } // end namespace llvm 19011c8dfa5SLang Hames 19111c8dfa5SLang Hames #undef DEBUG_TYPE // "jitlink" 19211c8dfa5SLang Hames 193c2cc70e4SQiu Chaofan #endif // LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 194