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 ExecutorAddr ResolverTargetAddr, 58 ExecutorAddr ReentryFnAddr, 59 ExecutorAddr ReentryCtxAddr) const = 0; 60 61 virtual void writeTrampolines(char *TrampolineBlockWorkingMem, 62 ExecutorAddr TrampolineBlockTragetAddr, 63 ExecutorAddr ResolverAddr, 64 unsigned NumTrampolines) const = 0; 65 66 virtual void writeIndirectStubsBlock( 67 char *StubsBlockWorkingMem, ExecutorAddr StubsBlockTargetAddress, 68 ExecutorAddr PointersBlockTargetAddress, unsigned NumStubs) const = 0; 69 70 private: 71 unsigned PointerSize = 0; 72 unsigned TrampolineSize = 0; 73 unsigned StubSize = 0; 74 unsigned StubToPointerMaxDisplacement = 0; 75 unsigned ResolverCodeSize = 0; 76 }; 77 78 /// Create using the given ABI class. 79 template <typename ORCABI> 80 static std::unique_ptr<EPCIndirectionUtils> 81 CreateWithABI(ExecutorProcessControl &EPC); 82 83 /// Create based on the ExecutorProcessControl triple. 84 static Expected<std::unique_ptr<EPCIndirectionUtils>> 85 Create(ExecutorProcessControl &EPC); 86 87 /// Create based on the ExecutorProcessControl triple. 88 static Expected<std::unique_ptr<EPCIndirectionUtils>> 89 Create(ExecutionSession &ES) { 90 return Create(ES.getExecutorProcessControl()); 91 } 92 93 /// Return a reference to the ExecutorProcessControl object. 94 ExecutorProcessControl &getExecutorProcessControl() const { return EPC; } 95 96 /// Return a reference to the ABISupport object for this instance. 97 ABISupport &getABISupport() const { return *ABI; } 98 99 /// Release memory for resources held by this instance. This *must* be called 100 /// prior to destruction of the class. 101 Error cleanup(); 102 103 /// Write resolver code to the executor process and return its address. 104 /// This must be called before any call to createTrampolinePool or 105 /// createLazyCallThroughManager. 106 Expected<ExecutorAddr> writeResolverBlock(ExecutorAddr ReentryFnAddr, 107 ExecutorAddr ReentryCtxAddr); 108 109 /// Returns the address of the Resolver block. Returns zero if the 110 /// writeResolverBlock method has not previously been called. 111 ExecutorAddr getResolverBlockAddress() const { return ResolverBlockAddr; } 112 113 /// Create an IndirectStubsManager for the executor process. 114 std::unique_ptr<IndirectStubsManager> createIndirectStubsManager(); 115 116 /// Create a TrampolinePool for the executor process. 117 TrampolinePool &getTrampolinePool(); 118 119 /// Create a LazyCallThroughManager. 120 /// This function should only be called once. 121 LazyCallThroughManager & 122 createLazyCallThroughManager(ExecutionSession &ES, 123 ExecutorAddr ErrorHandlerAddr); 124 125 /// Create a LazyCallThroughManager for the executor process. 126 LazyCallThroughManager &getLazyCallThroughManager() { 127 assert(LCTM && "createLazyCallThroughManager must be called first"); 128 return *LCTM; 129 } 130 131 private: 132 using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc; 133 134 struct IndirectStubInfo { 135 IndirectStubInfo() = default; 136 IndirectStubInfo(ExecutorAddr StubAddress, ExecutorAddr PointerAddress) 137 : StubAddress(StubAddress), PointerAddress(PointerAddress) {} 138 ExecutorAddr StubAddress; 139 ExecutorAddr PointerAddress; 140 }; 141 142 using IndirectStubInfoVector = std::vector<IndirectStubInfo>; 143 144 /// Create an EPCIndirectionUtils instance. 145 EPCIndirectionUtils(ExecutorProcessControl &EPC, 146 std::unique_ptr<ABISupport> ABI); 147 148 Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs); 149 150 std::mutex EPCUIMutex; 151 ExecutorProcessControl &EPC; 152 std::unique_ptr<ABISupport> ABI; 153 ExecutorAddr ResolverBlockAddr; 154 FinalizedAlloc ResolverBlock; 155 std::unique_ptr<TrampolinePool> TP; 156 std::unique_ptr<LazyCallThroughManager> LCTM; 157 158 std::vector<IndirectStubInfo> AvailableIndirectStubs; 159 std::vector<FinalizedAlloc> IndirectStubAllocs; 160 }; 161 162 /// This will call writeResolver on the given EPCIndirectionUtils instance 163 /// to set up re-entry via a function that will directly return the trampoline 164 /// landing address. 165 /// 166 /// The EPCIndirectionUtils' LazyCallThroughManager must have been previously 167 /// created via EPCIndirectionUtils::createLazyCallThroughManager. 168 /// 169 /// The EPCIndirectionUtils' writeResolver method must not have been previously 170 /// called. 171 /// 172 /// This function is experimental and likely subject to revision. 173 Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU); 174 175 namespace detail { 176 177 template <typename ORCABI> 178 class ABISupportImpl : public EPCIndirectionUtils::ABISupport { 179 public: 180 ABISupportImpl() 181 : ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize, 182 ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement, 183 ORCABI::ResolverCodeSize) {} 184 185 void writeResolverCode(char *ResolverWorkingMem, 186 ExecutorAddr ResolverTargetAddr, 187 ExecutorAddr ReentryFnAddr, 188 ExecutorAddr ReentryCtxAddr) const override { 189 ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr, 190 ReentryFnAddr, ReentryCtxAddr); 191 } 192 193 void writeTrampolines(char *TrampolineBlockWorkingMem, 194 ExecutorAddr TrampolineBlockTargetAddr, 195 ExecutorAddr ResolverAddr, 196 unsigned NumTrampolines) const override { 197 ORCABI::writeTrampolines(TrampolineBlockWorkingMem, 198 TrampolineBlockTargetAddr, ResolverAddr, 199 NumTrampolines); 200 } 201 202 void writeIndirectStubsBlock(char *StubsBlockWorkingMem, 203 ExecutorAddr StubsBlockTargetAddress, 204 ExecutorAddr PointersBlockTargetAddress, 205 unsigned NumStubs) const override { 206 ORCABI::writeIndirectStubsBlock(StubsBlockWorkingMem, 207 StubsBlockTargetAddress, 208 PointersBlockTargetAddress, NumStubs); 209 } 210 }; 211 212 } // end namespace detail 213 214 template <typename ORCABI> 215 std::unique_ptr<EPCIndirectionUtils> 216 EPCIndirectionUtils::CreateWithABI(ExecutorProcessControl &EPC) { 217 return std::unique_ptr<EPCIndirectionUtils>(new EPCIndirectionUtils( 218 EPC, std::make_unique<detail::ABISupportImpl<ORCABI>>())); 219 } 220 221 } // end namespace orc 222 } // end namespace llvm 223 224 #endif // LLVM_EXECUTIONENGINE_ORC_EPCINDIRECTIONUTILS_H 225