1 //===--- EPCIndirectionUtils.h - EPC based indirection utils ----*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // Indirection utilities (stubs, trampolines, lazy call-throughs) that use the 10 // ExecutorProcessControl API to interact with the executor process. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #ifndef LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H 15 #define LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H 16 17 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h" 18 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h" 19 #include "llvm/ExecutionEngine/Orc/LazyReexports.h" 20 21 #include <mutex> 22 23 namespace llvm { 24 namespace orc { 25 26 class ExecutorProcessControl; 27 28 /// Provides ExecutorProcessControl based indirect stubs, trampoline pool and 29 /// lazy call through manager. 30 class EPCIndirectionUtils { 31 friend class EPCIndirectionUtilsAccess; 32 33 public: 34 /// ABI support base class. Used to write resolver, stub, and trampoline 35 /// blocks. 36 class ABISupport { 37 protected: 38 ABISupport(unsigned PointerSize, unsigned TrampolineSize, unsigned StubSize, 39 unsigned StubToPointerMaxDisplacement, unsigned ResolverCodeSize) 40 : PointerSize(PointerSize), TrampolineSize(TrampolineSize), 41 StubSize(StubSize), 42 StubToPointerMaxDisplacement(StubToPointerMaxDisplacement), 43 ResolverCodeSize(ResolverCodeSize) {} 44 45 public: 46 virtual ~ABISupport(); 47 48 unsigned getPointerSize() const { return PointerSize; } 49 unsigned getTrampolineSize() const { return TrampolineSize; } 50 unsigned getStubSize() const { return StubSize; } 51 unsigned getStubToPointerMaxDisplacement() const { 52 return StubToPointerMaxDisplacement; 53 } 54 unsigned getResolverCodeSize() const { return ResolverCodeSize; } 55 56 virtual void writeResolverCode(char *ResolverWorkingMem, 57 JITTargetAddress ResolverTargetAddr, 58 JITTargetAddress ReentryFnAddr, 59 JITTargetAddress ReentryCtxAddr) const = 0; 60 61 virtual void writeTrampolines(char *TrampolineBlockWorkingMem, 62 JITTargetAddress TrampolineBlockTragetAddr, 63 JITTargetAddress ResolverAddr, 64 unsigned NumTrampolines) const = 0; 65 66 virtual void 67 writeIndirectStubsBlock(char *StubsBlockWorkingMem, 68 JITTargetAddress StubsBlockTargetAddress, 69 JITTargetAddress PointersBlockTargetAddress, 70 unsigned NumStubs) const = 0; 71 72 private: 73 unsigned PointerSize = 0; 74 unsigned TrampolineSize = 0; 75 unsigned StubSize = 0; 76 unsigned StubToPointerMaxDisplacement = 0; 77 unsigned ResolverCodeSize = 0; 78 }; 79 80 /// Create using the given ABI class. 81 template <typename ORCABI> 82 static std::unique_ptr<EPCIndirectionUtils> 83 CreateWithABI(ExecutorProcessControl &EPC); 84 85 /// Create based on the ExecutorProcessControl triple. 86 static Expected<std::unique_ptr<EPCIndirectionUtils>> 87 Create(ExecutorProcessControl &EPC); 88 89 /// Return a reference to the ExecutorProcessControl object. 90 ExecutorProcessControl &getExecutorProcessControl() const { return EPC; } 91 92 /// Return a reference to the ABISupport object for this instance. 93 ABISupport &getABISupport() const { return *ABI; } 94 95 /// Release memory for resources held by this instance. This *must* be called 96 /// prior to destruction of the class. 97 Error cleanup(); 98 99 /// Write resolver code to the executor process and return its address. 100 /// This must be called before any call to createTrampolinePool or 101 /// createLazyCallThroughManager. 102 Expected<JITTargetAddress> 103 writeResolverBlock(JITTargetAddress ReentryFnAddr, 104 JITTargetAddress ReentryCtxAddr); 105 106 /// Returns the address of the Resolver block. Returns zero if the 107 /// writeResolverBlock method has not previously been called. 108 JITTargetAddress getResolverBlockAddress() const { return ResolverBlockAddr; } 109 110 /// Create an IndirectStubsManager for the executor process. 111 std::unique_ptr<IndirectStubsManager> createIndirectStubsManager(); 112 113 /// Create a TrampolinePool for the executor process. 114 TrampolinePool &getTrampolinePool(); 115 116 /// Create a LazyCallThroughManager. 117 /// This function should only be called once. 118 LazyCallThroughManager & 119 createLazyCallThroughManager(ExecutionSession &ES, 120 JITTargetAddress ErrorHandlerAddr); 121 122 /// Create a LazyCallThroughManager for the executor process. 123 LazyCallThroughManager &getLazyCallThroughManager() { 124 assert(LCTM && "createLazyCallThroughManager must be called first"); 125 return *LCTM; 126 } 127 128 private: 129 using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc; 130 131 struct IndirectStubInfo { 132 IndirectStubInfo() = default; 133 IndirectStubInfo(JITTargetAddress StubAddress, 134 JITTargetAddress PointerAddress) 135 : StubAddress(StubAddress), PointerAddress(PointerAddress) {} 136 JITTargetAddress StubAddress = 0; 137 JITTargetAddress PointerAddress = 0; 138 }; 139 140 using IndirectStubInfoVector = std::vector<IndirectStubInfo>; 141 142 /// Create an EPCIndirectionUtils instance. 143 EPCIndirectionUtils(ExecutorProcessControl &EPC, 144 std::unique_ptr<ABISupport> ABI); 145 146 Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs); 147 148 std::mutex EPCUIMutex; 149 ExecutorProcessControl &EPC; 150 std::unique_ptr<ABISupport> ABI; 151 JITTargetAddress ResolverBlockAddr = 0; 152 FinalizedAlloc ResolverBlock; 153 std::unique_ptr<TrampolinePool> TP; 154 std::unique_ptr<LazyCallThroughManager> LCTM; 155 156 std::vector<IndirectStubInfo> AvailableIndirectStubs; 157 std::vector<FinalizedAlloc> IndirectStubAllocs; 158 }; 159 160 /// This will call writeResolver on the given EPCIndirectionUtils instance 161 /// to set up re-entry via a function that will directly return the trampoline 162 /// landing address. 163 /// 164 /// The EPCIndirectionUtils' LazyCallThroughManager must have been previously 165 /// created via EPCIndirectionUtils::createLazyCallThroughManager. 166 /// 167 /// The EPCIndirectionUtils' writeResolver method must not have been previously 168 /// called. 169 /// 170 /// This function is experimental and likely subject to revision. 171 Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU); 172 173 namespace detail { 174 175 template <typename ORCABI> 176 class ABISupportImpl : public EPCIndirectionUtils::ABISupport { 177 public: 178 ABISupportImpl() 179 : ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize, 180 ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement, 181 ORCABI::ResolverCodeSize) {} 182 183 void writeResolverCode(char *ResolverWorkingMem, 184 JITTargetAddress ResolverTargetAddr, 185 JITTargetAddress ReentryFnAddr, 186 JITTargetAddress ReentryCtxAddr) const override { 187 ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr, 188 ReentryFnAddr, ReentryCtxAddr); 189 } 190 191 void writeTrampolines(char *TrampolineBlockWorkingMem, 192 JITTargetAddress TrampolineBlockTargetAddr, 193 JITTargetAddress ResolverAddr, 194 unsigned NumTrampolines) const override { 195 ORCABI::writeTrampolines(TrampolineBlockWorkingMem, 196 TrampolineBlockTargetAddr, ResolverAddr, 197 NumTrampolines); 198 } 199 200 void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 201 JITTargetAddress StubsBlockTargetAddress, 202 JITTargetAddress PointersBlockTargetAddress, 203 unsigned NumStubs) const override { 204 ORCABI::writeIndirectStubsBlock(StubsBlockWorkingMem, 205 StubsBlockTargetAddress, 206 PointersBlockTargetAddress, NumStubs); 207 } 208 }; 209 210 } // end namespace detail 211 212 template <typename ORCABI> 213 std::unique_ptr<EPCIndirectionUtils> 214 EPCIndirectionUtils::CreateWithABI(ExecutorProcessControl &EPC) { 215 return std::unique_ptr<EPCIndirectionUtils>(new EPCIndirectionUtils( 216 EPC, std::make_unique<detail::ABISupportImpl<ORCABI>>())); 217 } 218 219 } // end namespace orc 220 } // end namespace llvm 221 222 #endif // LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H 223