1*da58b97aSjoerg //===------ TargetProcessControl.cpp -- Target process control APIs -------===//
2*da58b97aSjoerg //
3*da58b97aSjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*da58b97aSjoerg // See https://llvm.org/LICENSE.txt for license information.
5*da58b97aSjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*da58b97aSjoerg //
7*da58b97aSjoerg //===----------------------------------------------------------------------===//
8*da58b97aSjoerg 
9*da58b97aSjoerg #include "llvm/ExecutionEngine/Orc/TPCIndirectionUtils.h"
10*da58b97aSjoerg 
11*da58b97aSjoerg #include "llvm/ExecutionEngine/Orc/TargetProcessControl.h"
12*da58b97aSjoerg #include "llvm/Support/MathExtras.h"
13*da58b97aSjoerg 
14*da58b97aSjoerg #include <future>
15*da58b97aSjoerg 
16*da58b97aSjoerg using namespace llvm;
17*da58b97aSjoerg using namespace llvm::orc;
18*da58b97aSjoerg 
19*da58b97aSjoerg namespace llvm {
20*da58b97aSjoerg namespace orc {
21*da58b97aSjoerg 
22*da58b97aSjoerg class TPCIndirectionUtilsAccess {
23*da58b97aSjoerg public:
24*da58b97aSjoerg   using IndirectStubInfo = TPCIndirectionUtils::IndirectStubInfo;
25*da58b97aSjoerg   using IndirectStubInfoVector = TPCIndirectionUtils::IndirectStubInfoVector;
26*da58b97aSjoerg 
27*da58b97aSjoerg   static Expected<IndirectStubInfoVector>
getIndirectStubs(TPCIndirectionUtils & TPCIU,unsigned NumStubs)28*da58b97aSjoerg   getIndirectStubs(TPCIndirectionUtils &TPCIU, unsigned NumStubs) {
29*da58b97aSjoerg     return TPCIU.getIndirectStubs(NumStubs);
30*da58b97aSjoerg   };
31*da58b97aSjoerg };
32*da58b97aSjoerg 
33*da58b97aSjoerg } // end namespace orc
34*da58b97aSjoerg } // end namespace llvm
35*da58b97aSjoerg 
36*da58b97aSjoerg namespace {
37*da58b97aSjoerg 
38*da58b97aSjoerg class TPCTrampolinePool : public TrampolinePool {
39*da58b97aSjoerg public:
40*da58b97aSjoerg   TPCTrampolinePool(TPCIndirectionUtils &TPCIU);
41*da58b97aSjoerg   Error deallocatePool();
42*da58b97aSjoerg 
43*da58b97aSjoerg protected:
44*da58b97aSjoerg   Error grow() override;
45*da58b97aSjoerg 
46*da58b97aSjoerg   using Allocation = jitlink::JITLinkMemoryManager::Allocation;
47*da58b97aSjoerg 
48*da58b97aSjoerg   TPCIndirectionUtils &TPCIU;
49*da58b97aSjoerg   unsigned TrampolineSize = 0;
50*da58b97aSjoerg   unsigned TrampolinesPerPage = 0;
51*da58b97aSjoerg   std::vector<std::unique_ptr<Allocation>> TrampolineBlocks;
52*da58b97aSjoerg };
53*da58b97aSjoerg 
54*da58b97aSjoerg class TPCIndirectStubsManager : public IndirectStubsManager,
55*da58b97aSjoerg                                 private TPCIndirectionUtilsAccess {
56*da58b97aSjoerg public:
TPCIndirectStubsManager(TPCIndirectionUtils & TPCIU)57*da58b97aSjoerg   TPCIndirectStubsManager(TPCIndirectionUtils &TPCIU) : TPCIU(TPCIU) {}
58*da58b97aSjoerg 
59*da58b97aSjoerg   Error deallocateStubs();
60*da58b97aSjoerg 
61*da58b97aSjoerg   Error createStub(StringRef StubName, JITTargetAddress StubAddr,
62*da58b97aSjoerg                    JITSymbolFlags StubFlags) override;
63*da58b97aSjoerg 
64*da58b97aSjoerg   Error createStubs(const StubInitsMap &StubInits) override;
65*da58b97aSjoerg 
66*da58b97aSjoerg   JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override;
67*da58b97aSjoerg 
68*da58b97aSjoerg   JITEvaluatedSymbol findPointer(StringRef Name) override;
69*da58b97aSjoerg 
70*da58b97aSjoerg   Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override;
71*da58b97aSjoerg 
72*da58b97aSjoerg private:
73*da58b97aSjoerg   using StubInfo = std::pair<IndirectStubInfo, JITSymbolFlags>;
74*da58b97aSjoerg 
75*da58b97aSjoerg   std::mutex ISMMutex;
76*da58b97aSjoerg   TPCIndirectionUtils &TPCIU;
77*da58b97aSjoerg   StringMap<StubInfo> StubInfos;
78*da58b97aSjoerg };
79*da58b97aSjoerg 
TPCTrampolinePool(TPCIndirectionUtils & TPCIU)80*da58b97aSjoerg TPCTrampolinePool::TPCTrampolinePool(TPCIndirectionUtils &TPCIU)
81*da58b97aSjoerg     : TPCIU(TPCIU) {
82*da58b97aSjoerg   auto &TPC = TPCIU.getTargetProcessControl();
83*da58b97aSjoerg   auto &ABI = TPCIU.getABISupport();
84*da58b97aSjoerg 
85*da58b97aSjoerg   TrampolineSize = ABI.getTrampolineSize();
86*da58b97aSjoerg   TrampolinesPerPage =
87*da58b97aSjoerg       (TPC.getPageSize() - ABI.getPointerSize()) / TrampolineSize;
88*da58b97aSjoerg }
89*da58b97aSjoerg 
deallocatePool()90*da58b97aSjoerg Error TPCTrampolinePool::deallocatePool() {
91*da58b97aSjoerg   Error Err = Error::success();
92*da58b97aSjoerg   for (auto &Alloc : TrampolineBlocks)
93*da58b97aSjoerg     Err = joinErrors(std::move(Err), Alloc->deallocate());
94*da58b97aSjoerg   return Err;
95*da58b97aSjoerg }
96*da58b97aSjoerg 
grow()97*da58b97aSjoerg Error TPCTrampolinePool::grow() {
98*da58b97aSjoerg   assert(AvailableTrampolines.empty() &&
99*da58b97aSjoerg          "Grow called with trampolines still available");
100*da58b97aSjoerg 
101*da58b97aSjoerg   auto ResolverAddress = TPCIU.getResolverBlockAddress();
102*da58b97aSjoerg   assert(ResolverAddress && "Resolver address can not be null");
103*da58b97aSjoerg 
104*da58b97aSjoerg   auto &TPC = TPCIU.getTargetProcessControl();
105*da58b97aSjoerg   constexpr auto TrampolinePagePermissions =
106*da58b97aSjoerg       static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
107*da58b97aSjoerg                                                 sys::Memory::MF_EXEC);
108*da58b97aSjoerg   auto PageSize = TPC.getPageSize();
109*da58b97aSjoerg   jitlink::JITLinkMemoryManager::SegmentsRequestMap Request;
110*da58b97aSjoerg   Request[TrampolinePagePermissions] = {PageSize, static_cast<size_t>(PageSize),
111*da58b97aSjoerg                                         0};
112*da58b97aSjoerg   auto Alloc = TPC.getMemMgr().allocate(nullptr, Request);
113*da58b97aSjoerg 
114*da58b97aSjoerg   if (!Alloc)
115*da58b97aSjoerg     return Alloc.takeError();
116*da58b97aSjoerg 
117*da58b97aSjoerg   unsigned NumTrampolines = TrampolinesPerPage;
118*da58b97aSjoerg 
119*da58b97aSjoerg   auto WorkingMemory = (*Alloc)->getWorkingMemory(TrampolinePagePermissions);
120*da58b97aSjoerg   auto TargetAddress = (*Alloc)->getTargetMemory(TrampolinePagePermissions);
121*da58b97aSjoerg 
122*da58b97aSjoerg   TPCIU.getABISupport().writeTrampolines(WorkingMemory.data(), TargetAddress,
123*da58b97aSjoerg                                          ResolverAddress, NumTrampolines);
124*da58b97aSjoerg 
125*da58b97aSjoerg   auto TargetAddr = (*Alloc)->getTargetMemory(TrampolinePagePermissions);
126*da58b97aSjoerg   for (unsigned I = 0; I < NumTrampolines; ++I)
127*da58b97aSjoerg     AvailableTrampolines.push_back(TargetAddr + (I * TrampolineSize));
128*da58b97aSjoerg 
129*da58b97aSjoerg   if (auto Err = (*Alloc)->finalize())
130*da58b97aSjoerg     return Err;
131*da58b97aSjoerg 
132*da58b97aSjoerg   TrampolineBlocks.push_back(std::move(*Alloc));
133*da58b97aSjoerg 
134*da58b97aSjoerg   return Error::success();
135*da58b97aSjoerg }
136*da58b97aSjoerg 
createStub(StringRef StubName,JITTargetAddress StubAddr,JITSymbolFlags StubFlags)137*da58b97aSjoerg Error TPCIndirectStubsManager::createStub(StringRef StubName,
138*da58b97aSjoerg                                           JITTargetAddress StubAddr,
139*da58b97aSjoerg                                           JITSymbolFlags StubFlags) {
140*da58b97aSjoerg   StubInitsMap SIM;
141*da58b97aSjoerg   SIM[StubName] = std::make_pair(StubAddr, StubFlags);
142*da58b97aSjoerg   return createStubs(SIM);
143*da58b97aSjoerg }
144*da58b97aSjoerg 
createStubs(const StubInitsMap & StubInits)145*da58b97aSjoerg Error TPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
146*da58b97aSjoerg   auto AvailableStubInfos = getIndirectStubs(TPCIU, StubInits.size());
147*da58b97aSjoerg   if (!AvailableStubInfos)
148*da58b97aSjoerg     return AvailableStubInfos.takeError();
149*da58b97aSjoerg 
150*da58b97aSjoerg   {
151*da58b97aSjoerg     std::lock_guard<std::mutex> Lock(ISMMutex);
152*da58b97aSjoerg     unsigned ASIdx = 0;
153*da58b97aSjoerg     for (auto &SI : StubInits) {
154*da58b97aSjoerg       auto &A = (*AvailableStubInfos)[ASIdx++];
155*da58b97aSjoerg       StubInfos[SI.first()] = std::make_pair(A, SI.second.second);
156*da58b97aSjoerg     }
157*da58b97aSjoerg   }
158*da58b97aSjoerg 
159*da58b97aSjoerg   auto &MemAccess = TPCIU.getTargetProcessControl().getMemoryAccess();
160*da58b97aSjoerg   switch (TPCIU.getABISupport().getPointerSize()) {
161*da58b97aSjoerg   case 4: {
162*da58b97aSjoerg     unsigned ASIdx = 0;
163*da58b97aSjoerg     std::vector<tpctypes::UInt32Write> PtrUpdates;
164*da58b97aSjoerg     for (auto &SI : StubInits)
165*da58b97aSjoerg       PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
166*da58b97aSjoerg                             static_cast<uint32_t>(SI.second.first)});
167*da58b97aSjoerg     return MemAccess.writeUInt32s(PtrUpdates);
168*da58b97aSjoerg   }
169*da58b97aSjoerg   case 8: {
170*da58b97aSjoerg     unsigned ASIdx = 0;
171*da58b97aSjoerg     std::vector<tpctypes::UInt64Write> PtrUpdates;
172*da58b97aSjoerg     for (auto &SI : StubInits)
173*da58b97aSjoerg       PtrUpdates.push_back({(*AvailableStubInfos)[ASIdx++].PointerAddress,
174*da58b97aSjoerg                             static_cast<uint64_t>(SI.second.first)});
175*da58b97aSjoerg     return MemAccess.writeUInt64s(PtrUpdates);
176*da58b97aSjoerg   }
177*da58b97aSjoerg   default:
178*da58b97aSjoerg     return make_error<StringError>("Unsupported pointer size",
179*da58b97aSjoerg                                    inconvertibleErrorCode());
180*da58b97aSjoerg   }
181*da58b97aSjoerg }
182*da58b97aSjoerg 
findStub(StringRef Name,bool ExportedStubsOnly)183*da58b97aSjoerg JITEvaluatedSymbol TPCIndirectStubsManager::findStub(StringRef Name,
184*da58b97aSjoerg                                                      bool ExportedStubsOnly) {
185*da58b97aSjoerg   std::lock_guard<std::mutex> Lock(ISMMutex);
186*da58b97aSjoerg   auto I = StubInfos.find(Name);
187*da58b97aSjoerg   if (I == StubInfos.end())
188*da58b97aSjoerg     return nullptr;
189*da58b97aSjoerg   return {I->second.first.StubAddress, I->second.second};
190*da58b97aSjoerg }
191*da58b97aSjoerg 
findPointer(StringRef Name)192*da58b97aSjoerg JITEvaluatedSymbol TPCIndirectStubsManager::findPointer(StringRef Name) {
193*da58b97aSjoerg   std::lock_guard<std::mutex> Lock(ISMMutex);
194*da58b97aSjoerg   auto I = StubInfos.find(Name);
195*da58b97aSjoerg   if (I == StubInfos.end())
196*da58b97aSjoerg     return nullptr;
197*da58b97aSjoerg   return {I->second.first.PointerAddress, I->second.second};
198*da58b97aSjoerg }
199*da58b97aSjoerg 
updatePointer(StringRef Name,JITTargetAddress NewAddr)200*da58b97aSjoerg Error TPCIndirectStubsManager::updatePointer(StringRef Name,
201*da58b97aSjoerg                                              JITTargetAddress NewAddr) {
202*da58b97aSjoerg 
203*da58b97aSjoerg   JITTargetAddress PtrAddr = 0;
204*da58b97aSjoerg   {
205*da58b97aSjoerg     std::lock_guard<std::mutex> Lock(ISMMutex);
206*da58b97aSjoerg     auto I = StubInfos.find(Name);
207*da58b97aSjoerg     if (I == StubInfos.end())
208*da58b97aSjoerg       return make_error<StringError>("Unknown stub name",
209*da58b97aSjoerg                                      inconvertibleErrorCode());
210*da58b97aSjoerg     PtrAddr = I->second.first.PointerAddress;
211*da58b97aSjoerg   }
212*da58b97aSjoerg 
213*da58b97aSjoerg   auto &MemAccess = TPCIU.getTargetProcessControl().getMemoryAccess();
214*da58b97aSjoerg   switch (TPCIU.getABISupport().getPointerSize()) {
215*da58b97aSjoerg   case 4: {
216*da58b97aSjoerg     tpctypes::UInt32Write PUpdate(PtrAddr, NewAddr);
217*da58b97aSjoerg     return MemAccess.writeUInt32s(PUpdate);
218*da58b97aSjoerg   }
219*da58b97aSjoerg   case 8: {
220*da58b97aSjoerg     tpctypes::UInt64Write PUpdate(PtrAddr, NewAddr);
221*da58b97aSjoerg     return MemAccess.writeUInt64s(PUpdate);
222*da58b97aSjoerg   }
223*da58b97aSjoerg   default:
224*da58b97aSjoerg     return make_error<StringError>("Unsupported pointer size",
225*da58b97aSjoerg                                    inconvertibleErrorCode());
226*da58b97aSjoerg   }
227*da58b97aSjoerg }
228*da58b97aSjoerg 
229*da58b97aSjoerg } // end anonymous namespace.
230*da58b97aSjoerg 
231*da58b97aSjoerg namespace llvm {
232*da58b97aSjoerg namespace orc {
233*da58b97aSjoerg 
~ABISupport()234*da58b97aSjoerg TPCIndirectionUtils::ABISupport::~ABISupport() {}
235*da58b97aSjoerg 
236*da58b97aSjoerg Expected<std::unique_ptr<TPCIndirectionUtils>>
Create(TargetProcessControl & TPC)237*da58b97aSjoerg TPCIndirectionUtils::Create(TargetProcessControl &TPC) {
238*da58b97aSjoerg   const auto &TT = TPC.getTargetTriple();
239*da58b97aSjoerg   switch (TT.getArch()) {
240*da58b97aSjoerg   default:
241*da58b97aSjoerg     return make_error<StringError>(
242*da58b97aSjoerg         std::string("No TPCIndirectionUtils available for ") + TT.str(),
243*da58b97aSjoerg         inconvertibleErrorCode());
244*da58b97aSjoerg   case Triple::aarch64:
245*da58b97aSjoerg   case Triple::aarch64_32:
246*da58b97aSjoerg     return CreateWithABI<OrcAArch64>(TPC);
247*da58b97aSjoerg 
248*da58b97aSjoerg   case Triple::x86:
249*da58b97aSjoerg     return CreateWithABI<OrcI386>(TPC);
250*da58b97aSjoerg 
251*da58b97aSjoerg   case Triple::mips:
252*da58b97aSjoerg     return CreateWithABI<OrcMips32Be>(TPC);
253*da58b97aSjoerg 
254*da58b97aSjoerg   case Triple::mipsel:
255*da58b97aSjoerg     return CreateWithABI<OrcMips32Le>(TPC);
256*da58b97aSjoerg 
257*da58b97aSjoerg   case Triple::mips64:
258*da58b97aSjoerg   case Triple::mips64el:
259*da58b97aSjoerg     return CreateWithABI<OrcMips64>(TPC);
260*da58b97aSjoerg 
261*da58b97aSjoerg   case Triple::x86_64:
262*da58b97aSjoerg     if (TT.getOS() == Triple::OSType::Win32)
263*da58b97aSjoerg       return CreateWithABI<OrcX86_64_Win32>(TPC);
264*da58b97aSjoerg     else
265*da58b97aSjoerg       return CreateWithABI<OrcX86_64_SysV>(TPC);
266*da58b97aSjoerg   }
267*da58b97aSjoerg }
268*da58b97aSjoerg 
cleanup()269*da58b97aSjoerg Error TPCIndirectionUtils::cleanup() {
270*da58b97aSjoerg   Error Err = Error::success();
271*da58b97aSjoerg 
272*da58b97aSjoerg   for (auto &A : IndirectStubAllocs)
273*da58b97aSjoerg     Err = joinErrors(std::move(Err), A->deallocate());
274*da58b97aSjoerg 
275*da58b97aSjoerg   if (TP)
276*da58b97aSjoerg     Err = joinErrors(std::move(Err),
277*da58b97aSjoerg                      static_cast<TPCTrampolinePool &>(*TP).deallocatePool());
278*da58b97aSjoerg 
279*da58b97aSjoerg   if (ResolverBlock)
280*da58b97aSjoerg     Err = joinErrors(std::move(Err), ResolverBlock->deallocate());
281*da58b97aSjoerg 
282*da58b97aSjoerg   return Err;
283*da58b97aSjoerg }
284*da58b97aSjoerg 
285*da58b97aSjoerg Expected<JITTargetAddress>
writeResolverBlock(JITTargetAddress ReentryFnAddr,JITTargetAddress ReentryCtxAddr)286*da58b97aSjoerg TPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr,
287*da58b97aSjoerg                                         JITTargetAddress ReentryCtxAddr) {
288*da58b97aSjoerg   assert(ABI && "ABI can not be null");
289*da58b97aSjoerg   constexpr auto ResolverBlockPermissions =
290*da58b97aSjoerg       static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
291*da58b97aSjoerg                                                 sys::Memory::MF_EXEC);
292*da58b97aSjoerg   auto ResolverSize = ABI->getResolverCodeSize();
293*da58b97aSjoerg 
294*da58b97aSjoerg   jitlink::JITLinkMemoryManager::SegmentsRequestMap Request;
295*da58b97aSjoerg   Request[ResolverBlockPermissions] = {TPC.getPageSize(),
296*da58b97aSjoerg                                        static_cast<size_t>(ResolverSize), 0};
297*da58b97aSjoerg   auto Alloc = TPC.getMemMgr().allocate(nullptr, Request);
298*da58b97aSjoerg   if (!Alloc)
299*da58b97aSjoerg     return Alloc.takeError();
300*da58b97aSjoerg 
301*da58b97aSjoerg   auto WorkingMemory = (*Alloc)->getWorkingMemory(ResolverBlockPermissions);
302*da58b97aSjoerg   ResolverBlockAddr = (*Alloc)->getTargetMemory(ResolverBlockPermissions);
303*da58b97aSjoerg   ABI->writeResolverCode(WorkingMemory.data(), ResolverBlockAddr, ReentryFnAddr,
304*da58b97aSjoerg                          ReentryCtxAddr);
305*da58b97aSjoerg 
306*da58b97aSjoerg   if (auto Err = (*Alloc)->finalize())
307*da58b97aSjoerg     return std::move(Err);
308*da58b97aSjoerg 
309*da58b97aSjoerg   ResolverBlock = std::move(*Alloc);
310*da58b97aSjoerg   return ResolverBlockAddr;
311*da58b97aSjoerg }
312*da58b97aSjoerg 
313*da58b97aSjoerg std::unique_ptr<IndirectStubsManager>
createIndirectStubsManager()314*da58b97aSjoerg TPCIndirectionUtils::createIndirectStubsManager() {
315*da58b97aSjoerg   return std::make_unique<TPCIndirectStubsManager>(*this);
316*da58b97aSjoerg }
317*da58b97aSjoerg 
getTrampolinePool()318*da58b97aSjoerg TrampolinePool &TPCIndirectionUtils::getTrampolinePool() {
319*da58b97aSjoerg   if (!TP)
320*da58b97aSjoerg     TP = std::make_unique<TPCTrampolinePool>(*this);
321*da58b97aSjoerg   return *TP;
322*da58b97aSjoerg }
323*da58b97aSjoerg 
createLazyCallThroughManager(ExecutionSession & ES,JITTargetAddress ErrorHandlerAddr)324*da58b97aSjoerg LazyCallThroughManager &TPCIndirectionUtils::createLazyCallThroughManager(
325*da58b97aSjoerg     ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) {
326*da58b97aSjoerg   assert(!LCTM &&
327*da58b97aSjoerg          "createLazyCallThroughManager can not have been called before");
328*da58b97aSjoerg   LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
329*da58b97aSjoerg                                                   &getTrampolinePool());
330*da58b97aSjoerg   return *LCTM;
331*da58b97aSjoerg }
332*da58b97aSjoerg 
TPCIndirectionUtils(TargetProcessControl & TPC,std::unique_ptr<ABISupport> ABI)333*da58b97aSjoerg TPCIndirectionUtils::TPCIndirectionUtils(TargetProcessControl &TPC,
334*da58b97aSjoerg                                          std::unique_ptr<ABISupport> ABI)
335*da58b97aSjoerg     : TPC(TPC), ABI(std::move(ABI)) {
336*da58b97aSjoerg   assert(this->ABI && "ABI can not be null");
337*da58b97aSjoerg 
338*da58b97aSjoerg   assert(TPC.getPageSize() > getABISupport().getStubSize() &&
339*da58b97aSjoerg          "Stubs larger than one page are not supported");
340*da58b97aSjoerg }
341*da58b97aSjoerg 
342*da58b97aSjoerg Expected<TPCIndirectionUtils::IndirectStubInfoVector>
getIndirectStubs(unsigned NumStubs)343*da58b97aSjoerg TPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) {
344*da58b97aSjoerg 
345*da58b97aSjoerg   std::lock_guard<std::mutex> Lock(TPCUIMutex);
346*da58b97aSjoerg 
347*da58b97aSjoerg   // If there aren't enough stubs available then allocate some more.
348*da58b97aSjoerg   if (NumStubs > AvailableIndirectStubs.size()) {
349*da58b97aSjoerg     auto NumStubsToAllocate = NumStubs;
350*da58b97aSjoerg     auto PageSize = TPC.getPageSize();
351*da58b97aSjoerg     auto StubBytes = alignTo(NumStubsToAllocate * ABI->getStubSize(), PageSize);
352*da58b97aSjoerg     NumStubsToAllocate = StubBytes / ABI->getStubSize();
353*da58b97aSjoerg     auto PointerBytes =
354*da58b97aSjoerg         alignTo(NumStubsToAllocate * ABI->getPointerSize(), PageSize);
355*da58b97aSjoerg 
356*da58b97aSjoerg     constexpr auto StubPagePermissions =
357*da58b97aSjoerg         static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
358*da58b97aSjoerg                                                   sys::Memory::MF_EXEC);
359*da58b97aSjoerg     constexpr auto PointerPagePermissions =
360*da58b97aSjoerg         static_cast<sys::Memory::ProtectionFlags>(sys::Memory::MF_READ |
361*da58b97aSjoerg                                                   sys::Memory::MF_WRITE);
362*da58b97aSjoerg 
363*da58b97aSjoerg     jitlink::JITLinkMemoryManager::SegmentsRequestMap Request;
364*da58b97aSjoerg     Request[StubPagePermissions] = {PageSize, static_cast<size_t>(StubBytes),
365*da58b97aSjoerg                                     0};
366*da58b97aSjoerg     Request[PointerPagePermissions] = {PageSize, 0, PointerBytes};
367*da58b97aSjoerg     auto Alloc = TPC.getMemMgr().allocate(nullptr, Request);
368*da58b97aSjoerg     if (!Alloc)
369*da58b97aSjoerg       return Alloc.takeError();
370*da58b97aSjoerg 
371*da58b97aSjoerg     auto StubTargetAddr = (*Alloc)->getTargetMemory(StubPagePermissions);
372*da58b97aSjoerg     auto PointerTargetAddr = (*Alloc)->getTargetMemory(PointerPagePermissions);
373*da58b97aSjoerg 
374*da58b97aSjoerg     ABI->writeIndirectStubsBlock(
375*da58b97aSjoerg         (*Alloc)->getWorkingMemory(StubPagePermissions).data(), StubTargetAddr,
376*da58b97aSjoerg         PointerTargetAddr, NumStubsToAllocate);
377*da58b97aSjoerg 
378*da58b97aSjoerg     if (auto Err = (*Alloc)->finalize())
379*da58b97aSjoerg       return std::move(Err);
380*da58b97aSjoerg 
381*da58b97aSjoerg     for (unsigned I = 0; I != NumStubsToAllocate; ++I) {
382*da58b97aSjoerg       AvailableIndirectStubs.push_back(
383*da58b97aSjoerg           IndirectStubInfo(StubTargetAddr, PointerTargetAddr));
384*da58b97aSjoerg       StubTargetAddr += ABI->getStubSize();
385*da58b97aSjoerg       PointerTargetAddr += ABI->getPointerSize();
386*da58b97aSjoerg     }
387*da58b97aSjoerg 
388*da58b97aSjoerg     IndirectStubAllocs.push_back(std::move(*Alloc));
389*da58b97aSjoerg   }
390*da58b97aSjoerg 
391*da58b97aSjoerg   assert(NumStubs <= AvailableIndirectStubs.size() &&
392*da58b97aSjoerg          "Sufficient stubs should have been allocated above");
393*da58b97aSjoerg 
394*da58b97aSjoerg   IndirectStubInfoVector Result;
395*da58b97aSjoerg   while (NumStubs--) {
396*da58b97aSjoerg     Result.push_back(AvailableIndirectStubs.back());
397*da58b97aSjoerg     AvailableIndirectStubs.pop_back();
398*da58b97aSjoerg   }
399*da58b97aSjoerg 
400*da58b97aSjoerg   return std::move(Result);
401*da58b97aSjoerg }
402*da58b97aSjoerg 
reentry(JITTargetAddress LCTMAddr,JITTargetAddress TrampolineAddr)403*da58b97aSjoerg static JITTargetAddress reentry(JITTargetAddress LCTMAddr,
404*da58b97aSjoerg                                 JITTargetAddress TrampolineAddr) {
405*da58b97aSjoerg   auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
406*da58b97aSjoerg   std::promise<JITTargetAddress> LandingAddrP;
407*da58b97aSjoerg   auto LandingAddrF = LandingAddrP.get_future();
408*da58b97aSjoerg   LCTM.resolveTrampolineLandingAddress(
409*da58b97aSjoerg       TrampolineAddr,
410*da58b97aSjoerg       [&](JITTargetAddress Addr) { LandingAddrP.set_value(Addr); });
411*da58b97aSjoerg   return LandingAddrF.get();
412*da58b97aSjoerg }
413*da58b97aSjoerg 
setUpInProcessLCTMReentryViaTPCIU(TPCIndirectionUtils & TPCIU)414*da58b97aSjoerg Error setUpInProcessLCTMReentryViaTPCIU(TPCIndirectionUtils &TPCIU) {
415*da58b97aSjoerg   auto &LCTM = TPCIU.getLazyCallThroughManager();
416*da58b97aSjoerg   return TPCIU
417*da58b97aSjoerg       .writeResolverBlock(pointerToJITTargetAddress(&reentry),
418*da58b97aSjoerg                           pointerToJITTargetAddress(&LCTM))
419*da58b97aSjoerg       .takeError();
420*da58b97aSjoerg }
421*da58b97aSjoerg 
422*da58b97aSjoerg } // end namespace orc
423*da58b97aSjoerg } // end namespace llvm
424