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/ADT/DenseSet.h" 170b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h" 180b57cec5SDimitry Andric 190b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink" 200b57cec5SDimitry Andric 210b57cec5SDimitry Andric namespace llvm { 220b57cec5SDimitry Andric namespace jitlink { 230b57cec5SDimitry Andric 240b57cec5SDimitry Andric /// Base class for a JIT linker. 250b57cec5SDimitry Andric /// 260b57cec5SDimitry Andric /// A JITLinkerBase instance links one object file into an ongoing JIT 270b57cec5SDimitry Andric /// session. Symbol resolution and finalization operations are pluggable, 280b57cec5SDimitry Andric /// and called using continuation passing (passing a continuation for the 290b57cec5SDimitry Andric /// remaining linker work) to allow them to be performed asynchronously. 300b57cec5SDimitry Andric class JITLinkerBase { 310b57cec5SDimitry Andric public: 32e8d8bef9SDimitry Andric JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, 33e8d8bef9SDimitry Andric std::unique_ptr<LinkGraph> G, PassConfiguration Passes) 34e8d8bef9SDimitry Andric : Ctx(std::move(Ctx)), G(std::move(G)), Passes(std::move(Passes)) { 350b57cec5SDimitry Andric assert(this->Ctx && "Ctx can not be null"); 36e8d8bef9SDimitry Andric assert(this->G && "G can not be null"); 370b57cec5SDimitry Andric } 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric virtual ~JITLinkerBase(); 400b57cec5SDimitry Andric 410b57cec5SDimitry Andric protected: 42349cc55cSDimitry Andric using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc; 43349cc55cSDimitry Andric using AllocResult = Expected<std::unique_ptr<InFlightAlloc>>; 44349cc55cSDimitry Andric using FinalizeResult = Expected<JITLinkMemoryManager::FinalizedAlloc>; 450b57cec5SDimitry Andric 46fe6060f1SDimitry Andric // Returns the PassConfiguration for this instance. This can be used by 47fe6060f1SDimitry Andric // JITLinkerBase implementations to add late passes that reference their 48fe6060f1SDimitry Andric // own data structures (e.g. for ELF implementations to locate / construct 49fe6060f1SDimitry Andric // a GOT start symbol prior to fixup). 50fe6060f1SDimitry Andric PassConfiguration &getPassConfig() { return Passes; } 51fe6060f1SDimitry Andric 520b57cec5SDimitry Andric // Phase 1: 53e8d8bef9SDimitry Andric // 1.1: Run pre-prune passes 540b57cec5SDimitry Andric // 1.2: Prune graph 550b57cec5SDimitry Andric // 1.3: Run post-prune passes 56349cc55cSDimitry Andric // 1.4: Allocate memory. 570b57cec5SDimitry Andric void linkPhase1(std::unique_ptr<JITLinkerBase> Self); 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric // Phase 2: 60349cc55cSDimitry Andric // 2.2: Run post-allocation passes 61349cc55cSDimitry Andric // 2.3: Notify context of final assigned symbol addresses 62349cc55cSDimitry Andric // 2.4: Identify external symbols and make an async call to resolve 63349cc55cSDimitry Andric void linkPhase2(std::unique_ptr<JITLinkerBase> Self, AllocResult AR); 640b57cec5SDimitry Andric 650b57cec5SDimitry Andric // Phase 3: 66349cc55cSDimitry Andric // 3.1: Apply resolution results 67349cc55cSDimitry Andric // 3.2: Run pre-fixup passes 68349cc55cSDimitry Andric // 3.3: Fix up block contents 69349cc55cSDimitry Andric // 3.4: Run post-fixup passes 70349cc55cSDimitry Andric // 3.5: Make an async call to transfer and finalize memory. 71349cc55cSDimitry Andric void linkPhase3(std::unique_ptr<JITLinkerBase> Self, 72349cc55cSDimitry Andric Expected<AsyncLookupResult> LookupResult); 730b57cec5SDimitry Andric 74349cc55cSDimitry Andric // Phase 4: 75349cc55cSDimitry Andric // 4.1: Call OnFinalized callback, handing off allocation. 76349cc55cSDimitry Andric void linkPhase4(std::unique_ptr<JITLinkerBase> Self, FinalizeResult FR); 778bcb0991SDimitry Andric 780b57cec5SDimitry Andric private: 790b57cec5SDimitry Andric // Run all passes in the given pass list, bailing out immediately if any pass 800b57cec5SDimitry Andric // returns an error. 818bcb0991SDimitry Andric Error runPasses(LinkGraphPassList &Passes); 820b57cec5SDimitry Andric 838bcb0991SDimitry Andric // Copy block contents and apply relocations. 840b57cec5SDimitry Andric // Implemented in JITLinker. 855ffd83dbSDimitry Andric virtual Error fixUpBlocks(LinkGraph &G) const = 0; 860b57cec5SDimitry Andric 87480093f4SDimitry Andric JITLinkContext::LookupMap getExternalSymbolNames() const; 880b57cec5SDimitry Andric void applyLookupResult(AsyncLookupResult LR); 89349cc55cSDimitry Andric void abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self, Error Err); 900b57cec5SDimitry Andric 910b57cec5SDimitry Andric std::unique_ptr<JITLinkContext> Ctx; 928bcb0991SDimitry Andric std::unique_ptr<LinkGraph> G; 93e8d8bef9SDimitry Andric PassConfiguration Passes; 94349cc55cSDimitry Andric std::unique_ptr<InFlightAlloc> Alloc; 950b57cec5SDimitry Andric }; 960b57cec5SDimitry Andric 970b57cec5SDimitry Andric template <typename LinkerImpl> class JITLinker : public JITLinkerBase { 980b57cec5SDimitry Andric public: 990b57cec5SDimitry Andric using JITLinkerBase::JITLinkerBase; 1000b57cec5SDimitry Andric 1010b57cec5SDimitry Andric /// Link constructs a LinkerImpl instance and calls linkPhase1. 1020b57cec5SDimitry Andric /// Link should be called with the constructor arguments for LinkerImpl, which 1030b57cec5SDimitry Andric /// will be forwarded to the constructor. 1040b57cec5SDimitry Andric template <typename... ArgTs> static void link(ArgTs &&... Args) { 1058bcb0991SDimitry Andric auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...); 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric // Ownership of the linker is passed into the linker's doLink function to 1080b57cec5SDimitry Andric // allow it to be passed on to async continuations. 1090b57cec5SDimitry Andric // 1100b57cec5SDimitry Andric // FIXME: Remove LTmp once we have c++17. 1110b57cec5SDimitry Andric // C++17 sequencing rules guarantee that function name expressions are 1120b57cec5SDimitry Andric // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be 1130b57cec5SDimitry Andric // well formed. 1140b57cec5SDimitry Andric auto <mp = *L; 1150b57cec5SDimitry Andric LTmp.linkPhase1(std::move(L)); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric private: 1190b57cec5SDimitry Andric const LinkerImpl &impl() const { 1200b57cec5SDimitry Andric return static_cast<const LinkerImpl &>(*this); 1210b57cec5SDimitry Andric } 1220b57cec5SDimitry Andric 1235ffd83dbSDimitry Andric Error fixUpBlocks(LinkGraph &G) const override { 1245ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Fixing up blocks:\n"); 1250b57cec5SDimitry Andric 1265ffd83dbSDimitry Andric for (auto *B : G.blocks()) { 1278bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << " " << *B << ":\n"); 1280b57cec5SDimitry Andric 1298bcb0991SDimitry Andric // Copy Block data and apply fixups. 1300b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Applying fixups.\n"); 131349cc55cSDimitry Andric assert((!B->isZeroFill() || B->edges_size() == 0) && 132349cc55cSDimitry Andric "Edges in zero-fill block?"); 1338bcb0991SDimitry Andric for (auto &E : B->edges()) { 1340b57cec5SDimitry Andric 1350b57cec5SDimitry Andric // Skip non-relocation edges. 1360b57cec5SDimitry Andric if (!E.isRelocation()) 1370b57cec5SDimitry Andric continue; 1380b57cec5SDimitry Andric 1390b57cec5SDimitry Andric // Dispatch to LinkerImpl for fixup. 140fe6060f1SDimitry Andric if (auto Err = impl().applyFixup(G, *B, E)) 1410b57cec5SDimitry Andric return Err; 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric 1450b57cec5SDimitry Andric return Error::success(); 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric }; 1480b57cec5SDimitry Andric 1498bcb0991SDimitry Andric /// Removes dead symbols/blocks/addressables. 1500b57cec5SDimitry Andric /// 1518bcb0991SDimitry Andric /// Finds the set of symbols and addressables reachable from any symbol 1528bcb0991SDimitry Andric /// initially marked live. All symbols/addressables not marked live at the end 1538bcb0991SDimitry Andric /// of this process are removed. 1548bcb0991SDimitry Andric void prune(LinkGraph &G); 1550b57cec5SDimitry Andric 1560b57cec5SDimitry Andric } // end namespace jitlink 1570b57cec5SDimitry Andric } // end namespace llvm 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric #undef DEBUG_TYPE // "jitlink" 1600b57cec5SDimitry Andric 161*04eeddc0SDimitry Andric #endif // LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 162