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 230b57cec5SDimitry Andric class MemoryBufferRef; 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric namespace jitlink { 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric /// Base class for a JIT linker. 280b57cec5SDimitry Andric /// 290b57cec5SDimitry Andric /// A JITLinkerBase instance links one object file into an ongoing JIT 300b57cec5SDimitry Andric /// session. Symbol resolution and finalization operations are pluggable, 310b57cec5SDimitry Andric /// and called using continuation passing (passing a continuation for the 320b57cec5SDimitry Andric /// remaining linker work) to allow them to be performed asynchronously. 330b57cec5SDimitry Andric class JITLinkerBase { 340b57cec5SDimitry Andric public: 35e8d8bef9SDimitry Andric JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, 36e8d8bef9SDimitry Andric std::unique_ptr<LinkGraph> G, PassConfiguration Passes) 37e8d8bef9SDimitry Andric : Ctx(std::move(Ctx)), G(std::move(G)), Passes(std::move(Passes)) { 380b57cec5SDimitry Andric assert(this->Ctx && "Ctx can not be null"); 39e8d8bef9SDimitry Andric assert(this->G && "G can not be null"); 400b57cec5SDimitry Andric } 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric virtual ~JITLinkerBase(); 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric protected: 45*349cc55cSDimitry Andric using InFlightAlloc = JITLinkMemoryManager::InFlightAlloc; 46*349cc55cSDimitry Andric using AllocResult = Expected<std::unique_ptr<InFlightAlloc>>; 47*349cc55cSDimitry Andric using FinalizeResult = Expected<JITLinkMemoryManager::FinalizedAlloc>; 480b57cec5SDimitry Andric 49fe6060f1SDimitry Andric // Returns the PassConfiguration for this instance. This can be used by 50fe6060f1SDimitry Andric // JITLinkerBase implementations to add late passes that reference their 51fe6060f1SDimitry Andric // own data structures (e.g. for ELF implementations to locate / construct 52fe6060f1SDimitry Andric // a GOT start symbol prior to fixup). 53fe6060f1SDimitry Andric PassConfiguration &getPassConfig() { return Passes; } 54fe6060f1SDimitry Andric 550b57cec5SDimitry Andric // Phase 1: 56e8d8bef9SDimitry Andric // 1.1: Run pre-prune passes 570b57cec5SDimitry Andric // 1.2: Prune graph 580b57cec5SDimitry Andric // 1.3: Run post-prune passes 59*349cc55cSDimitry Andric // 1.4: Allocate memory. 600b57cec5SDimitry Andric void linkPhase1(std::unique_ptr<JITLinkerBase> Self); 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric // Phase 2: 63*349cc55cSDimitry Andric // 2.2: Run post-allocation passes 64*349cc55cSDimitry Andric // 2.3: Notify context of final assigned symbol addresses 65*349cc55cSDimitry Andric // 2.4: Identify external symbols and make an async call to resolve 66*349cc55cSDimitry Andric void linkPhase2(std::unique_ptr<JITLinkerBase> Self, AllocResult AR); 670b57cec5SDimitry Andric 680b57cec5SDimitry Andric // Phase 3: 69*349cc55cSDimitry Andric // 3.1: Apply resolution results 70*349cc55cSDimitry Andric // 3.2: Run pre-fixup passes 71*349cc55cSDimitry Andric // 3.3: Fix up block contents 72*349cc55cSDimitry Andric // 3.4: Run post-fixup passes 73*349cc55cSDimitry Andric // 3.5: Make an async call to transfer and finalize memory. 74*349cc55cSDimitry Andric void linkPhase3(std::unique_ptr<JITLinkerBase> Self, 75*349cc55cSDimitry Andric Expected<AsyncLookupResult> LookupResult); 760b57cec5SDimitry Andric 77*349cc55cSDimitry Andric // Phase 4: 78*349cc55cSDimitry Andric // 4.1: Call OnFinalized callback, handing off allocation. 79*349cc55cSDimitry Andric void linkPhase4(std::unique_ptr<JITLinkerBase> Self, FinalizeResult FR); 808bcb0991SDimitry Andric 810b57cec5SDimitry Andric private: 820b57cec5SDimitry Andric // Run all passes in the given pass list, bailing out immediately if any pass 830b57cec5SDimitry Andric // returns an error. 848bcb0991SDimitry Andric Error runPasses(LinkGraphPassList &Passes); 850b57cec5SDimitry Andric 868bcb0991SDimitry Andric // Copy block contents and apply relocations. 870b57cec5SDimitry Andric // Implemented in JITLinker. 885ffd83dbSDimitry Andric virtual Error fixUpBlocks(LinkGraph &G) const = 0; 890b57cec5SDimitry Andric 90480093f4SDimitry Andric JITLinkContext::LookupMap getExternalSymbolNames() const; 910b57cec5SDimitry Andric void applyLookupResult(AsyncLookupResult LR); 92*349cc55cSDimitry Andric void abandonAllocAndBailOut(std::unique_ptr<JITLinkerBase> Self, Error Err); 930b57cec5SDimitry Andric 940b57cec5SDimitry Andric std::unique_ptr<JITLinkContext> Ctx; 958bcb0991SDimitry Andric std::unique_ptr<LinkGraph> G; 96e8d8bef9SDimitry Andric PassConfiguration Passes; 97*349cc55cSDimitry Andric std::unique_ptr<InFlightAlloc> Alloc; 980b57cec5SDimitry Andric }; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric template <typename LinkerImpl> class JITLinker : public JITLinkerBase { 1010b57cec5SDimitry Andric public: 1020b57cec5SDimitry Andric using JITLinkerBase::JITLinkerBase; 1030b57cec5SDimitry Andric 1040b57cec5SDimitry Andric /// Link constructs a LinkerImpl instance and calls linkPhase1. 1050b57cec5SDimitry Andric /// Link should be called with the constructor arguments for LinkerImpl, which 1060b57cec5SDimitry Andric /// will be forwarded to the constructor. 1070b57cec5SDimitry Andric template <typename... ArgTs> static void link(ArgTs &&... Args) { 1088bcb0991SDimitry Andric auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...); 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric // Ownership of the linker is passed into the linker's doLink function to 1110b57cec5SDimitry Andric // allow it to be passed on to async continuations. 1120b57cec5SDimitry Andric // 1130b57cec5SDimitry Andric // FIXME: Remove LTmp once we have c++17. 1140b57cec5SDimitry Andric // C++17 sequencing rules guarantee that function name expressions are 1150b57cec5SDimitry Andric // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be 1160b57cec5SDimitry Andric // well formed. 1170b57cec5SDimitry Andric auto <mp = *L; 1180b57cec5SDimitry Andric LTmp.linkPhase1(std::move(L)); 1190b57cec5SDimitry Andric } 1200b57cec5SDimitry Andric 1210b57cec5SDimitry Andric private: 1220b57cec5SDimitry Andric const LinkerImpl &impl() const { 1230b57cec5SDimitry Andric return static_cast<const LinkerImpl &>(*this); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1265ffd83dbSDimitry Andric Error fixUpBlocks(LinkGraph &G) const override { 1275ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "Fixing up blocks:\n"); 1280b57cec5SDimitry Andric 1295ffd83dbSDimitry Andric for (auto *B : G.blocks()) { 1308bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << " " << *B << ":\n"); 1310b57cec5SDimitry Andric 1328bcb0991SDimitry Andric // Copy Block data and apply fixups. 1330b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Applying fixups.\n"); 134*349cc55cSDimitry Andric assert((!B->isZeroFill() || B->edges_size() == 0) && 135*349cc55cSDimitry Andric "Edges in zero-fill block?"); 1368bcb0991SDimitry Andric for (auto &E : B->edges()) { 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric // Skip non-relocation edges. 1390b57cec5SDimitry Andric if (!E.isRelocation()) 1400b57cec5SDimitry Andric continue; 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric // Dispatch to LinkerImpl for fixup. 143fe6060f1SDimitry Andric if (auto Err = impl().applyFixup(G, *B, E)) 1440b57cec5SDimitry Andric return Err; 1450b57cec5SDimitry Andric } 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric return Error::success(); 1490b57cec5SDimitry Andric } 1500b57cec5SDimitry Andric }; 1510b57cec5SDimitry Andric 1528bcb0991SDimitry Andric /// Removes dead symbols/blocks/addressables. 1530b57cec5SDimitry Andric /// 1548bcb0991SDimitry Andric /// Finds the set of symbols and addressables reachable from any symbol 1558bcb0991SDimitry Andric /// initially marked live. All symbols/addressables not marked live at the end 1568bcb0991SDimitry Andric /// of this process are removed. 1578bcb0991SDimitry Andric void prune(LinkGraph &G); 1580b57cec5SDimitry Andric 1590b57cec5SDimitry Andric } // end namespace jitlink 1600b57cec5SDimitry Andric } // end namespace llvm 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric #undef DEBUG_TYPE // "jitlink" 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 165