106f32e7eSjoerg //===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===// 206f32e7eSjoerg // 306f32e7eSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 406f32e7eSjoerg // See https://llvm.org/LICENSE.txt for license information. 506f32e7eSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 606f32e7eSjoerg // 706f32e7eSjoerg //===----------------------------------------------------------------------===// 806f32e7eSjoerg // 906f32e7eSjoerg // Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing. 1006f32e7eSjoerg // 1106f32e7eSjoerg //===----------------------------------------------------------------------===// 1206f32e7eSjoerg 1306f32e7eSjoerg #ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 1406f32e7eSjoerg #define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 1506f32e7eSjoerg 1606f32e7eSjoerg #include "llvm/ADT/DenseSet.h" 1706f32e7eSjoerg #include "llvm/ExecutionEngine/JITLink/JITLink.h" 1806f32e7eSjoerg 1906f32e7eSjoerg #define DEBUG_TYPE "jitlink" 2006f32e7eSjoerg 2106f32e7eSjoerg namespace llvm { 2206f32e7eSjoerg 2306f32e7eSjoerg class MemoryBufferRef; 2406f32e7eSjoerg 2506f32e7eSjoerg namespace jitlink { 2606f32e7eSjoerg 2706f32e7eSjoerg /// Base class for a JIT linker. 2806f32e7eSjoerg /// 2906f32e7eSjoerg /// A JITLinkerBase instance links one object file into an ongoing JIT 3006f32e7eSjoerg /// session. Symbol resolution and finalization operations are pluggable, 3106f32e7eSjoerg /// and called using continuation passing (passing a continuation for the 3206f32e7eSjoerg /// remaining linker work) to allow them to be performed asynchronously. 3306f32e7eSjoerg class JITLinkerBase { 3406f32e7eSjoerg public: JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx,std::unique_ptr<LinkGraph> G,PassConfiguration Passes)35*da58b97aSjoerg JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, 36*da58b97aSjoerg std::unique_ptr<LinkGraph> G, PassConfiguration Passes) 37*da58b97aSjoerg : Ctx(std::move(Ctx)), G(std::move(G)), Passes(std::move(Passes)) { 3806f32e7eSjoerg assert(this->Ctx && "Ctx can not be null"); 39*da58b97aSjoerg assert(this->G && "G can not be null"); 4006f32e7eSjoerg } 4106f32e7eSjoerg 4206f32e7eSjoerg virtual ~JITLinkerBase(); 4306f32e7eSjoerg 4406f32e7eSjoerg protected: 4506f32e7eSjoerg struct SegmentLayout { 4606f32e7eSjoerg using BlocksList = std::vector<Block *>; 4706f32e7eSjoerg 4806f32e7eSjoerg BlocksList ContentBlocks; 4906f32e7eSjoerg BlocksList ZeroFillBlocks; 5006f32e7eSjoerg }; 5106f32e7eSjoerg 5206f32e7eSjoerg using SegmentLayoutMap = DenseMap<unsigned, SegmentLayout>; 5306f32e7eSjoerg 54*da58b97aSjoerg // Returns the PassConfiguration for this instance. This can be used by 55*da58b97aSjoerg // JITLinkerBase implementations to add late passes that reference their 56*da58b97aSjoerg // own data structures (e.g. for ELF implementations to locate / construct 57*da58b97aSjoerg // a GOT start symbol prior to fixup). getPassConfig()58*da58b97aSjoerg PassConfiguration &getPassConfig() { return Passes; } 59*da58b97aSjoerg 6006f32e7eSjoerg // Phase 1: 61*da58b97aSjoerg // 1.1: Run pre-prune passes 6206f32e7eSjoerg // 1.2: Prune graph 6306f32e7eSjoerg // 1.3: Run post-prune passes 6406f32e7eSjoerg // 1.4: Sort blocks into segments 65*da58b97aSjoerg // 1.5: Allocate segment memory, update node vmaddrs to target vmaddrs 66*da58b97aSjoerg // 1.6: Run post-allocation passes 67*da58b97aSjoerg // 1.7: Notify context of final assigned symbol addresses 68*da58b97aSjoerg // 1.8: Identify external symbols and make an async call to resolve 6906f32e7eSjoerg void linkPhase1(std::unique_ptr<JITLinkerBase> Self); 7006f32e7eSjoerg 7106f32e7eSjoerg // Phase 2: 7206f32e7eSjoerg // 2.1: Apply resolution results 73*da58b97aSjoerg // 2.2: Run pre-fixup passes 74*da58b97aSjoerg // 2.3: Fix up block contents 75*da58b97aSjoerg // 2.4: Run post-fixup passes 76*da58b97aSjoerg // 2.5: Make an async call to transfer and finalize memory. 7706f32e7eSjoerg void linkPhase2(std::unique_ptr<JITLinkerBase> Self, 7806f32e7eSjoerg Expected<AsyncLookupResult> LookupResult, 7906f32e7eSjoerg SegmentLayoutMap Layout); 8006f32e7eSjoerg 8106f32e7eSjoerg // Phase 3: 8206f32e7eSjoerg // 3.1: Call OnFinalized callback, handing off allocation. 8306f32e7eSjoerg void linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err); 8406f32e7eSjoerg 85*da58b97aSjoerg // Align a JITTargetAddress to conform with block alignment requirements. alignToBlock(JITTargetAddress Addr,Block & B)8606f32e7eSjoerg static JITTargetAddress alignToBlock(JITTargetAddress Addr, Block &B) { 8706f32e7eSjoerg uint64_t Delta = (B.getAlignmentOffset() - Addr) % B.getAlignment(); 8806f32e7eSjoerg return Addr + Delta; 8906f32e7eSjoerg } 9006f32e7eSjoerg 91*da58b97aSjoerg // Align a pointer to conform with block alignment requirements. alignToBlock(char * P,Block & B)9206f32e7eSjoerg static char *alignToBlock(char *P, Block &B) { 9306f32e7eSjoerg uint64_t PAddr = static_cast<uint64_t>(reinterpret_cast<uintptr_t>(P)); 9406f32e7eSjoerg uint64_t Delta = (B.getAlignmentOffset() - PAddr) % B.getAlignment(); 9506f32e7eSjoerg return P + Delta; 9606f32e7eSjoerg } 9706f32e7eSjoerg 9806f32e7eSjoerg private: 9906f32e7eSjoerg // Run all passes in the given pass list, bailing out immediately if any pass 10006f32e7eSjoerg // returns an error. 10106f32e7eSjoerg Error runPasses(LinkGraphPassList &Passes); 10206f32e7eSjoerg 10306f32e7eSjoerg // Copy block contents and apply relocations. 10406f32e7eSjoerg // Implemented in JITLinker. 105*da58b97aSjoerg virtual Error fixUpBlocks(LinkGraph &G) const = 0; 10606f32e7eSjoerg 10706f32e7eSjoerg SegmentLayoutMap layOutBlocks(); 10806f32e7eSjoerg Error allocateSegments(const SegmentLayoutMap &Layout); 109*da58b97aSjoerg JITLinkContext::LookupMap getExternalSymbolNames() const; 11006f32e7eSjoerg void applyLookupResult(AsyncLookupResult LR); 111*da58b97aSjoerg void copyBlockContentToWorkingMemory(const SegmentLayoutMap &Layout, 112*da58b97aSjoerg JITLinkMemoryManager::Allocation &Alloc); 11306f32e7eSjoerg void deallocateAndBailOut(Error Err); 11406f32e7eSjoerg 11506f32e7eSjoerg std::unique_ptr<JITLinkContext> Ctx; 11606f32e7eSjoerg std::unique_ptr<LinkGraph> G; 117*da58b97aSjoerg PassConfiguration Passes; 11806f32e7eSjoerg std::unique_ptr<JITLinkMemoryManager::Allocation> Alloc; 11906f32e7eSjoerg }; 12006f32e7eSjoerg 12106f32e7eSjoerg template <typename LinkerImpl> class JITLinker : public JITLinkerBase { 12206f32e7eSjoerg public: 12306f32e7eSjoerg using JITLinkerBase::JITLinkerBase; 12406f32e7eSjoerg 12506f32e7eSjoerg /// Link constructs a LinkerImpl instance and calls linkPhase1. 12606f32e7eSjoerg /// Link should be called with the constructor arguments for LinkerImpl, which 12706f32e7eSjoerg /// will be forwarded to the constructor. link(ArgTs &&...Args)12806f32e7eSjoerg template <typename... ArgTs> static void link(ArgTs &&... Args) { 12906f32e7eSjoerg auto L = std::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...); 13006f32e7eSjoerg 13106f32e7eSjoerg // Ownership of the linker is passed into the linker's doLink function to 13206f32e7eSjoerg // allow it to be passed on to async continuations. 13306f32e7eSjoerg // 13406f32e7eSjoerg // FIXME: Remove LTmp once we have c++17. 13506f32e7eSjoerg // C++17 sequencing rules guarantee that function name expressions are 13606f32e7eSjoerg // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be 13706f32e7eSjoerg // well formed. 13806f32e7eSjoerg auto <mp = *L; 13906f32e7eSjoerg LTmp.linkPhase1(std::move(L)); 14006f32e7eSjoerg } 14106f32e7eSjoerg 14206f32e7eSjoerg private: impl()14306f32e7eSjoerg const LinkerImpl &impl() const { 14406f32e7eSjoerg return static_cast<const LinkerImpl &>(*this); 14506f32e7eSjoerg } 14606f32e7eSjoerg fixUpBlocks(LinkGraph & G)147*da58b97aSjoerg Error fixUpBlocks(LinkGraph &G) const override { 148*da58b97aSjoerg LLVM_DEBUG(dbgs() << "Fixing up blocks:\n"); 14906f32e7eSjoerg 150*da58b97aSjoerg for (auto *B : G.blocks()) { 15106f32e7eSjoerg LLVM_DEBUG(dbgs() << " " << *B << ":\n"); 15206f32e7eSjoerg 15306f32e7eSjoerg // Copy Block data and apply fixups. 15406f32e7eSjoerg LLVM_DEBUG(dbgs() << " Applying fixups.\n"); 15506f32e7eSjoerg for (auto &E : B->edges()) { 15606f32e7eSjoerg 15706f32e7eSjoerg // Skip non-relocation edges. 15806f32e7eSjoerg if (!E.isRelocation()) 15906f32e7eSjoerg continue; 16006f32e7eSjoerg 16106f32e7eSjoerg // Dispatch to LinkerImpl for fixup. 162*da58b97aSjoerg auto *BlockData = const_cast<char *>(B->getContent().data()); 163*da58b97aSjoerg if (auto Err = impl().applyFixup(G, *B, E, BlockData)) 16406f32e7eSjoerg return Err; 16506f32e7eSjoerg } 16606f32e7eSjoerg } 16706f32e7eSjoerg 16806f32e7eSjoerg return Error::success(); 16906f32e7eSjoerg } 17006f32e7eSjoerg }; 17106f32e7eSjoerg 17206f32e7eSjoerg /// Removes dead symbols/blocks/addressables. 17306f32e7eSjoerg /// 17406f32e7eSjoerg /// Finds the set of symbols and addressables reachable from any symbol 17506f32e7eSjoerg /// initially marked live. All symbols/addressables not marked live at the end 17606f32e7eSjoerg /// of this process are removed. 17706f32e7eSjoerg void prune(LinkGraph &G); 17806f32e7eSjoerg 17906f32e7eSjoerg } // end namespace jitlink 18006f32e7eSjoerg } // end namespace llvm 18106f32e7eSjoerg 18206f32e7eSjoerg #undef DEBUG_TYPE // "jitlink" 18306f32e7eSjoerg 18406f32e7eSjoerg #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 185