1*0b57cec5SDimitry Andric //===------ JITLinkGeneric.h - Generic JIT linker utilities -----*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // Generic JITLinker utilities. E.g. graph pruning, eh-frame parsing. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 12*0b57cec5SDimitry Andric 13*0b57cec5SDimitry Andric #ifndef LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 14*0b57cec5SDimitry Andric #define LIB_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 15*0b57cec5SDimitry Andric 16*0b57cec5SDimitry Andric #include "llvm/ADT/DenseSet.h" 17*0b57cec5SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h" 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric #define DEBUG_TYPE "jitlink" 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric namespace llvm { 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric class MemoryBufferRef; 24*0b57cec5SDimitry Andric 25*0b57cec5SDimitry Andric namespace jitlink { 26*0b57cec5SDimitry Andric 27*0b57cec5SDimitry Andric /// Base class for a JIT linker. 28*0b57cec5SDimitry Andric /// 29*0b57cec5SDimitry Andric /// A JITLinkerBase instance links one object file into an ongoing JIT 30*0b57cec5SDimitry Andric /// session. Symbol resolution and finalization operations are pluggable, 31*0b57cec5SDimitry Andric /// and called using continuation passing (passing a continuation for the 32*0b57cec5SDimitry Andric /// remaining linker work) to allow them to be performed asynchronously. 33*0b57cec5SDimitry Andric class JITLinkerBase { 34*0b57cec5SDimitry Andric public: 35*0b57cec5SDimitry Andric JITLinkerBase(std::unique_ptr<JITLinkContext> Ctx, PassConfiguration Passes) 36*0b57cec5SDimitry Andric : Ctx(std::move(Ctx)), Passes(std::move(Passes)) { 37*0b57cec5SDimitry Andric assert(this->Ctx && "Ctx can not be null"); 38*0b57cec5SDimitry Andric } 39*0b57cec5SDimitry Andric 40*0b57cec5SDimitry Andric virtual ~JITLinkerBase(); 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric protected: 43*0b57cec5SDimitry Andric struct SegmentLayout { 44*0b57cec5SDimitry Andric using SectionAtomsList = std::vector<DefinedAtom *>; 45*0b57cec5SDimitry Andric struct SectionLayout { 46*0b57cec5SDimitry Andric SectionLayout(Section &S) : S(&S) {} 47*0b57cec5SDimitry Andric 48*0b57cec5SDimitry Andric Section *S; 49*0b57cec5SDimitry Andric SectionAtomsList Atoms; 50*0b57cec5SDimitry Andric }; 51*0b57cec5SDimitry Andric 52*0b57cec5SDimitry Andric using SectionLayoutList = std::vector<SectionLayout>; 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric SectionLayoutList ContentSections; 55*0b57cec5SDimitry Andric SectionLayoutList ZeroFillSections; 56*0b57cec5SDimitry Andric }; 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric using SegmentLayoutMap = DenseMap<unsigned, SegmentLayout>; 59*0b57cec5SDimitry Andric 60*0b57cec5SDimitry Andric // Phase 1: 61*0b57cec5SDimitry Andric // 1.1: Build atom graph 62*0b57cec5SDimitry Andric // 1.2: Run pre-prune passes 63*0b57cec5SDimitry Andric // 1.2: Prune graph 64*0b57cec5SDimitry Andric // 1.3: Run post-prune passes 65*0b57cec5SDimitry Andric // 1.4: Sort atoms into segments 66*0b57cec5SDimitry Andric // 1.5: Allocate segment memory 67*0b57cec5SDimitry Andric // 1.6: Identify externals and make an async call to resolve function 68*0b57cec5SDimitry Andric void linkPhase1(std::unique_ptr<JITLinkerBase> Self); 69*0b57cec5SDimitry Andric 70*0b57cec5SDimitry Andric // Phase 2: 71*0b57cec5SDimitry Andric // 2.1: Apply resolution results 72*0b57cec5SDimitry Andric // 2.2: Fix up atom contents 73*0b57cec5SDimitry Andric // 2.3: Call OnResolved callback 74*0b57cec5SDimitry Andric // 2.3: Make an async call to transfer and finalize memory. 75*0b57cec5SDimitry Andric void linkPhase2(std::unique_ptr<JITLinkerBase> Self, 76*0b57cec5SDimitry Andric Expected<AsyncLookupResult> LookupResult); 77*0b57cec5SDimitry Andric 78*0b57cec5SDimitry Andric // Phase 3: 79*0b57cec5SDimitry Andric // 3.1: Call OnFinalized callback, handing off allocation. 80*0b57cec5SDimitry Andric void linkPhase3(std::unique_ptr<JITLinkerBase> Self, Error Err); 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric // Build a graph from the given object buffer. 83*0b57cec5SDimitry Andric // To be implemented by the client. 84*0b57cec5SDimitry Andric virtual Expected<std::unique_ptr<AtomGraph>> 85*0b57cec5SDimitry Andric buildGraph(MemoryBufferRef ObjBuffer) = 0; 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric // For debug dumping of the atom graph. 88*0b57cec5SDimitry Andric virtual StringRef getEdgeKindName(Edge::Kind K) const = 0; 89*0b57cec5SDimitry Andric 90*0b57cec5SDimitry Andric private: 91*0b57cec5SDimitry Andric // Run all passes in the given pass list, bailing out immediately if any pass 92*0b57cec5SDimitry Andric // returns an error. 93*0b57cec5SDimitry Andric Error runPasses(AtomGraphPassList &Passes, AtomGraph &G); 94*0b57cec5SDimitry Andric 95*0b57cec5SDimitry Andric // Copy atom contents and apply relocations. 96*0b57cec5SDimitry Andric // Implemented in JITLinker. 97*0b57cec5SDimitry Andric virtual Error 98*0b57cec5SDimitry Andric copyAndFixUpAllAtoms(const SegmentLayoutMap &Layout, 99*0b57cec5SDimitry Andric JITLinkMemoryManager::Allocation &Alloc) const = 0; 100*0b57cec5SDimitry Andric 101*0b57cec5SDimitry Andric void layOutAtoms(); 102*0b57cec5SDimitry Andric Error allocateSegments(const SegmentLayoutMap &Layout); 103*0b57cec5SDimitry Andric DenseSet<StringRef> getExternalSymbolNames() const; 104*0b57cec5SDimitry Andric void applyLookupResult(AsyncLookupResult LR); 105*0b57cec5SDimitry Andric void deallocateAndBailOut(Error Err); 106*0b57cec5SDimitry Andric 107*0b57cec5SDimitry Andric void dumpGraph(raw_ostream &OS); 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric std::unique_ptr<JITLinkContext> Ctx; 110*0b57cec5SDimitry Andric PassConfiguration Passes; 111*0b57cec5SDimitry Andric std::unique_ptr<AtomGraph> G; 112*0b57cec5SDimitry Andric SegmentLayoutMap Layout; 113*0b57cec5SDimitry Andric std::unique_ptr<JITLinkMemoryManager::Allocation> Alloc; 114*0b57cec5SDimitry Andric }; 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric template <typename LinkerImpl> class JITLinker : public JITLinkerBase { 117*0b57cec5SDimitry Andric public: 118*0b57cec5SDimitry Andric using JITLinkerBase::JITLinkerBase; 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric /// Link constructs a LinkerImpl instance and calls linkPhase1. 121*0b57cec5SDimitry Andric /// Link should be called with the constructor arguments for LinkerImpl, which 122*0b57cec5SDimitry Andric /// will be forwarded to the constructor. 123*0b57cec5SDimitry Andric template <typename... ArgTs> static void link(ArgTs &&... Args) { 124*0b57cec5SDimitry Andric auto L = llvm::make_unique<LinkerImpl>(std::forward<ArgTs>(Args)...); 125*0b57cec5SDimitry Andric 126*0b57cec5SDimitry Andric // Ownership of the linker is passed into the linker's doLink function to 127*0b57cec5SDimitry Andric // allow it to be passed on to async continuations. 128*0b57cec5SDimitry Andric // 129*0b57cec5SDimitry Andric // FIXME: Remove LTmp once we have c++17. 130*0b57cec5SDimitry Andric // C++17 sequencing rules guarantee that function name expressions are 131*0b57cec5SDimitry Andric // sequenced before arguments, so L->linkPhase1(std::move(L), ...) will be 132*0b57cec5SDimitry Andric // well formed. 133*0b57cec5SDimitry Andric auto <mp = *L; 134*0b57cec5SDimitry Andric LTmp.linkPhase1(std::move(L)); 135*0b57cec5SDimitry Andric } 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric private: 138*0b57cec5SDimitry Andric const LinkerImpl &impl() const { 139*0b57cec5SDimitry Andric return static_cast<const LinkerImpl &>(*this); 140*0b57cec5SDimitry Andric } 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric Error 143*0b57cec5SDimitry Andric copyAndFixUpAllAtoms(const SegmentLayoutMap &Layout, 144*0b57cec5SDimitry Andric JITLinkMemoryManager::Allocation &Alloc) const override { 145*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Copying and fixing up atoms:\n"); 146*0b57cec5SDimitry Andric for (auto &KV : Layout) { 147*0b57cec5SDimitry Andric auto &Prot = KV.first; 148*0b57cec5SDimitry Andric auto &SegLayout = KV.second; 149*0b57cec5SDimitry Andric 150*0b57cec5SDimitry Andric auto SegMem = Alloc.getWorkingMemory( 151*0b57cec5SDimitry Andric static_cast<sys::Memory::ProtectionFlags>(Prot)); 152*0b57cec5SDimitry Andric char *LastAtomEnd = SegMem.data(); 153*0b57cec5SDimitry Andric char *AtomDataPtr = LastAtomEnd; 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric LLVM_DEBUG({ 156*0b57cec5SDimitry Andric dbgs() << " Processing segment " 157*0b57cec5SDimitry Andric << static_cast<sys::Memory::ProtectionFlags>(Prot) << " [ " 158*0b57cec5SDimitry Andric << (const void *)SegMem.data() << " .. " 159*0b57cec5SDimitry Andric << (const void *)((char *)SegMem.data() + SegMem.size()) 160*0b57cec5SDimitry Andric << " ]\n Processing content sections:\n"; 161*0b57cec5SDimitry Andric }); 162*0b57cec5SDimitry Andric 163*0b57cec5SDimitry Andric for (auto &SI : SegLayout.ContentSections) { 164*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " " << SI.S->getName() << ":\n"); 165*0b57cec5SDimitry Andric 166*0b57cec5SDimitry Andric AtomDataPtr += alignmentAdjustment(AtomDataPtr, SI.S->getAlignment()); 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric LLVM_DEBUG({ 169*0b57cec5SDimitry Andric dbgs() << " Bumped atom pointer to " << (const void *)AtomDataPtr 170*0b57cec5SDimitry Andric << " to meet section alignment " 171*0b57cec5SDimitry Andric << " of " << SI.S->getAlignment() << "\n"; 172*0b57cec5SDimitry Andric }); 173*0b57cec5SDimitry Andric 174*0b57cec5SDimitry Andric for (auto *DA : SI.Atoms) { 175*0b57cec5SDimitry Andric 176*0b57cec5SDimitry Andric // Align. 177*0b57cec5SDimitry Andric AtomDataPtr += alignmentAdjustment(AtomDataPtr, DA->getAlignment()); 178*0b57cec5SDimitry Andric LLVM_DEBUG({ 179*0b57cec5SDimitry Andric dbgs() << " Bumped atom pointer to " 180*0b57cec5SDimitry Andric << (const void *)AtomDataPtr << " to meet alignment of " 181*0b57cec5SDimitry Andric << DA->getAlignment() << "\n"; 182*0b57cec5SDimitry Andric }); 183*0b57cec5SDimitry Andric 184*0b57cec5SDimitry Andric // Zero pad up to alignment. 185*0b57cec5SDimitry Andric LLVM_DEBUG({ 186*0b57cec5SDimitry Andric if (LastAtomEnd != AtomDataPtr) 187*0b57cec5SDimitry Andric dbgs() << " Zero padding from " << (const void *)LastAtomEnd 188*0b57cec5SDimitry Andric << " to " << (const void *)AtomDataPtr << "\n"; 189*0b57cec5SDimitry Andric }); 190*0b57cec5SDimitry Andric while (LastAtomEnd != AtomDataPtr) 191*0b57cec5SDimitry Andric *LastAtomEnd++ = 0; 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric // Copy initial atom content. 194*0b57cec5SDimitry Andric LLVM_DEBUG({ 195*0b57cec5SDimitry Andric dbgs() << " Copying atom " << *DA << " content, " 196*0b57cec5SDimitry Andric << DA->getContent().size() << " bytes, from " 197*0b57cec5SDimitry Andric << (const void *)DA->getContent().data() << " to " 198*0b57cec5SDimitry Andric << (const void *)AtomDataPtr << "\n"; 199*0b57cec5SDimitry Andric }); 200*0b57cec5SDimitry Andric memcpy(AtomDataPtr, DA->getContent().data(), DA->getContent().size()); 201*0b57cec5SDimitry Andric 202*0b57cec5SDimitry Andric // Copy atom data and apply fixups. 203*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Applying fixups.\n"); 204*0b57cec5SDimitry Andric for (auto &E : DA->edges()) { 205*0b57cec5SDimitry Andric 206*0b57cec5SDimitry Andric // Skip non-relocation edges. 207*0b57cec5SDimitry Andric if (!E.isRelocation()) 208*0b57cec5SDimitry Andric continue; 209*0b57cec5SDimitry Andric 210*0b57cec5SDimitry Andric // Dispatch to LinkerImpl for fixup. 211*0b57cec5SDimitry Andric if (auto Err = impl().applyFixup(*DA, E, AtomDataPtr)) 212*0b57cec5SDimitry Andric return Err; 213*0b57cec5SDimitry Andric } 214*0b57cec5SDimitry Andric 215*0b57cec5SDimitry Andric // Point the atom's content to the fixed up buffer. 216*0b57cec5SDimitry Andric DA->setContent(StringRef(AtomDataPtr, DA->getContent().size())); 217*0b57cec5SDimitry Andric 218*0b57cec5SDimitry Andric // Update atom end pointer. 219*0b57cec5SDimitry Andric LastAtomEnd = AtomDataPtr + DA->getContent().size(); 220*0b57cec5SDimitry Andric AtomDataPtr = LastAtomEnd; 221*0b57cec5SDimitry Andric } 222*0b57cec5SDimitry Andric } 223*0b57cec5SDimitry Andric 224*0b57cec5SDimitry Andric // Zero pad the rest of the segment. 225*0b57cec5SDimitry Andric LLVM_DEBUG({ 226*0b57cec5SDimitry Andric dbgs() << " Zero padding end of segment from " 227*0b57cec5SDimitry Andric << (const void *)LastAtomEnd << " to " 228*0b57cec5SDimitry Andric << (const void *)((char *)SegMem.data() + SegMem.size()) << "\n"; 229*0b57cec5SDimitry Andric }); 230*0b57cec5SDimitry Andric while (LastAtomEnd != SegMem.data() + SegMem.size()) 231*0b57cec5SDimitry Andric *LastAtomEnd++ = 0; 232*0b57cec5SDimitry Andric } 233*0b57cec5SDimitry Andric 234*0b57cec5SDimitry Andric return Error::success(); 235*0b57cec5SDimitry Andric } 236*0b57cec5SDimitry Andric }; 237*0b57cec5SDimitry Andric 238*0b57cec5SDimitry Andric /// Dead strips and replaces discarded definitions with external atoms. 239*0b57cec5SDimitry Andric /// 240*0b57cec5SDimitry Andric /// Finds the set of nodes reachable from any node initially marked live 241*0b57cec5SDimitry Andric /// (nodes marked should-discard are treated as not live, even if they are 242*0b57cec5SDimitry Andric /// reachable). All nodes not marked as live at the end of this process, 243*0b57cec5SDimitry Andric /// are deleted. Nodes that are live, but marked should-discard are replaced 244*0b57cec5SDimitry Andric /// with external atoms and all edges to them are re-written. 245*0b57cec5SDimitry Andric void prune(AtomGraph &G); 246*0b57cec5SDimitry Andric 247*0b57cec5SDimitry Andric Error addEHFrame(AtomGraph &G, Section &EHFrameSection, 248*0b57cec5SDimitry Andric StringRef EHFrameContent, JITTargetAddress EHFrameAddress, 249*0b57cec5SDimitry Andric Edge::Kind FDEToCIERelocKind, Edge::Kind FDEToTargetRelocKind); 250*0b57cec5SDimitry Andric 251*0b57cec5SDimitry Andric } // end namespace jitlink 252*0b57cec5SDimitry Andric } // end namespace llvm 253*0b57cec5SDimitry Andric 254*0b57cec5SDimitry Andric #undef DEBUG_TYPE // "jitlink" 255*0b57cec5SDimitry Andric 256*0b57cec5SDimitry Andric #endif // LLVM_EXECUTIONENGINE_JITLINK_JITLINKGENERIC_H 257