1 //===--- TPCIndirectionUtils.h - TPC based indirection utils ----*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Indirection utilities (stubs, trampolines, lazy call-throughs) that use the
10 // TargetProcessControl API to interact with the target process.
12 //===----------------------------------------------------------------------===//
14 #ifndef LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H
15 #define LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H
17 #include "llvm/ExecutionEngine/JITLink/JITLinkMemoryManager.h"
18 #include "llvm/ExecutionEngine/Orc/IndirectionUtils.h"
19 #include "llvm/ExecutionEngine/Orc/LazyReexports.h"
26 class TargetProcessControl;
28 /// Provides TargetProcessControl based indirect stubs, trampoline pool and
29 /// lazy call through manager.
30 class TPCIndirectionUtils {
31 friend class TPCIndirectionUtilsAccess;
34 /// ABI support base class. Used to write resolver, stub, and trampoline
38 ABISupport(unsigned PointerSize, unsigned TrampolineSize, unsigned StubSize,
39 unsigned StubToPointerMaxDisplacement, unsigned ResolverCodeSize)
40 : PointerSize(PointerSize), TrampolineSize(TrampolineSize),
42 StubToPointerMaxDisplacement(StubToPointerMaxDisplacement),
43 ResolverCodeSize(ResolverCodeSize) {}
46 virtual ~ABISupport();
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;
54 unsigned getResolverCodeSize() const { return ResolverCodeSize; }
56 virtual void writeResolverCode(char *ResolverWorkingMem,
57 JITTargetAddress ResolverTargetAddr,
58 JITTargetAddress ReentryFnAddr,
59 JITTargetAddress ReentryCtxAddr) const = 0;
61 virtual void writeTrampolines(char *TrampolineBlockWorkingMem,
62 JITTargetAddress TrampolineBlockTragetAddr,
63 JITTargetAddress ResolverAddr,
64 unsigned NumTrampolines) const = 0;
67 writeIndirectStubsBlock(char *StubsBlockWorkingMem,
68 JITTargetAddress StubsBlockTargetAddress,
69 JITTargetAddress PointersBlockTargetAddress,
70 unsigned NumStubs) const = 0;
73 unsigned PointerSize = 0;
74 unsigned TrampolineSize = 0;
75 unsigned StubSize = 0;
76 unsigned StubToPointerMaxDisplacement = 0;
77 unsigned ResolverCodeSize = 0;
80 /// Create using the given ABI class.
81 template <typename ORCABI>
82 static std::unique_ptr<TPCIndirectionUtils>
83 CreateWithABI(TargetProcessControl &TPC);
85 /// Create based on the TargetProcessControl triple.
86 static Expected<std::unique_ptr<TPCIndirectionUtils>>
87 Create(TargetProcessControl &TPC);
89 /// Return a reference to the TargetProcessControl object.
90 TargetProcessControl &getTargetProcessControl() const { return TPC; }
92 /// Return a reference to the ABISupport object for this instance.
93 ABISupport &getABISupport() const { return *ABI; }
95 /// Release memory for resources held by this instance. This *must* be called
96 /// prior to destruction of the class.
99 /// Write resolver code to the target 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);
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; }
110 /// Create an IndirectStubsManager for the target process.
111 std::unique_ptr<IndirectStubsManager> createIndirectStubsManager();
113 /// Create a TrampolinePool for the target process.
114 TrampolinePool &getTrampolinePool();
116 /// Create a LazyCallThroughManager.
117 /// This function should only be called once.
118 LazyCallThroughManager &
119 createLazyCallThroughManager(ExecutionSession &ES,
120 JITTargetAddress ErrorHandlerAddr);
122 /// Create a LazyCallThroughManager for the target process.
123 LazyCallThroughManager &getLazyCallThroughManager() {
124 assert(LCTM && "createLazyCallThroughManager must be called first");
129 using Allocation = jitlink::JITLinkMemoryManager::Allocation;
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;
140 using IndirectStubInfoVector = std::vector<IndirectStubInfo>;
142 /// Create a TPCIndirectionUtils instance.
143 TPCIndirectionUtils(TargetProcessControl &TPC,
144 std::unique_ptr<ABISupport> ABI);
146 Expected<IndirectStubInfoVector> getIndirectStubs(unsigned NumStubs);
148 std::mutex TPCUIMutex;
149 TargetProcessControl &TPC;
150 std::unique_ptr<ABISupport> ABI;
151 JITTargetAddress ResolverBlockAddr;
152 std::unique_ptr<jitlink::JITLinkMemoryManager::Allocation> ResolverBlock;
153 std::unique_ptr<TrampolinePool> TP;
154 std::unique_ptr<LazyCallThroughManager> LCTM;
156 std::vector<IndirectStubInfo> AvailableIndirectStubs;
157 std::vector<std::unique_ptr<Allocation>> IndirectStubAllocs;
160 /// This will call writeResolver on the given TPCIndirectionUtils instance
161 /// to set up re-entry via a function that will directly return the trampoline
164 /// The TPCIndirectionUtils' LazyCallThroughManager must have been previously
165 /// created via TPCIndirectionUtils::createLazyCallThroughManager.
167 /// The TPCIndirectionUtils' writeResolver method must not have been previously
170 /// This function is experimental and likely subject to revision.
171 Error setUpInProcessLCTMReentryViaTPCIU(TPCIndirectionUtils &TPCIU);
175 template <typename ORCABI>
176 class ABISupportImpl : public TPCIndirectionUtils::ABISupport {
179 : ABISupport(ORCABI::PointerSize, ORCABI::TrampolineSize,
180 ORCABI::StubSize, ORCABI::StubToPointerMaxDisplacement,
181 ORCABI::ResolverCodeSize) {}
183 void writeResolverCode(char *ResolverWorkingMem,
184 JITTargetAddress ResolverTargetAddr,
185 JITTargetAddress ReentryFnAddr,
186 JITTargetAddress ReentryCtxAddr) const override {
187 ORCABI::writeResolverCode(ResolverWorkingMem, ResolverTargetAddr,
188 ReentryFnAddr, ReentryCtxAddr);
191 void writeTrampolines(char *TrampolineBlockWorkingMem,
192 JITTargetAddress TrampolineBlockTargetAddr,
193 JITTargetAddress ResolverAddr,
194 unsigned NumTrampolines) const override {
195 ORCABI::writeTrampolines(TrampolineBlockWorkingMem,
196 TrampolineBlockTargetAddr, ResolverAddr,
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);
210 } // end namespace detail
212 template <typename ORCABI>
213 std::unique_ptr<TPCIndirectionUtils>
214 TPCIndirectionUtils::CreateWithABI(TargetProcessControl &TPC) {
215 return std::unique_ptr<TPCIndirectionUtils>(new TPCIndirectionUtils(
216 TPC, std::make_unique<detail::ABISupportImpl<ORCABI>>()));
219 } // end namespace orc
220 } // end namespace llvm
222 #endif // LLVM_EXECUTIONENGINE_ORC_TPCINDIRECTIONUTILS_H