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