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 23namespace llvm { 24namespace orc { 25 26class ExecutorProcessControl; 27 28/// Provides ExecutorProcessControl based indirect stubs, trampoline pool and 29/// lazy call through manager. 30class EPCIndirectionUtils { 31 friend class EPCIndirectionUtilsAccess; 32 33public: 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 131private: 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. 173Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU); 174 175namespace detail { 176 177template <typename ORCABI> 178class ABISupportImpl : public EPCIndirectionUtils::ABISupport { 179public: 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 214template <typename ORCABI> 215std::unique_ptr<EPCIndirectionUtils> 216EPCIndirectionUtils::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