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 &LTmp = *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