123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427 |
- //===------- EPCIndirectionUtils.cpp -- EPC based indirection APIs --------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #include "llvm/ExecutionEngine/Orc/EPCIndirectionUtils.h"
- #include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
- #include "llvm/Support/MathExtras.h"
- #include <future>
- using namespace llvm;
- using namespace llvm::orc;
- namespace llvm {
- namespace orc {
- class EPCIndirectionUtilsAccess {
- public:
- using IndirectStubInfo = EPCIndirectionUtils::IndirectStubInfo;
- using IndirectStubInfoVector = EPCIndirectionUtils::IndirectStubInfoVector;
- static Expected<IndirectStubInfoVector>
- getIndirectStubs(EPCIndirectionUtils &EPCIU, unsigned NumStubs) {
- return EPCIU.getIndirectStubs(NumStubs);
- };
- };
- } // end namespace orc
- } // end namespace llvm
- namespace {
- class EPCTrampolinePool : public TrampolinePool {
- public:
- EPCTrampolinePool(EPCIndirectionUtils &EPCIU);
- Error deallocatePool();
- protected:
- Error grow() override;
- using FinalizedAlloc = jitlink::JITLinkMemoryManager::FinalizedAlloc;
- EPCIndirectionUtils &EPCIU;
- unsigned TrampolineSize = 0;
- unsigned TrampolinesPerPage = 0;
- std::vector<FinalizedAlloc> TrampolineBlocks;
- };
- class EPCIndirectStubsManager : public IndirectStubsManager,
- private EPCIndirectionUtilsAccess {
- public:
- EPCIndirectStubsManager(EPCIndirectionUtils &EPCIU) : EPCIU(EPCIU) {}
- Error deallocateStubs();
- Error createStub(StringRef StubName, JITTargetAddress StubAddr,
- JITSymbolFlags StubFlags) override;
- Error createStubs(const StubInitsMap &StubInits) override;
- JITEvaluatedSymbol findStub(StringRef Name, bool ExportedStubsOnly) override;
- JITEvaluatedSymbol findPointer(StringRef Name) override;
- Error updatePointer(StringRef Name, JITTargetAddress NewAddr) override;
- private:
- using StubInfo = std::pair<IndirectStubInfo, JITSymbolFlags>;
- std::mutex ISMMutex;
- EPCIndirectionUtils &EPCIU;
- StringMap<StubInfo> StubInfos;
- };
- EPCTrampolinePool::EPCTrampolinePool(EPCIndirectionUtils &EPCIU)
- : EPCIU(EPCIU) {
- auto &EPC = EPCIU.getExecutorProcessControl();
- auto &ABI = EPCIU.getABISupport();
- TrampolineSize = ABI.getTrampolineSize();
- TrampolinesPerPage =
- (EPC.getPageSize() - ABI.getPointerSize()) / TrampolineSize;
- }
- Error EPCTrampolinePool::deallocatePool() {
- Error Err = Error::success();
- std::promise<MSVCPError> DeallocResultP;
- auto DeallocResultF = DeallocResultP.get_future();
- EPCIU.getExecutorProcessControl().getMemMgr().deallocate(
- std::move(TrampolineBlocks),
- [&](Error Err) { DeallocResultP.set_value(std::move(Err)); });
- return DeallocResultF.get();
- }
- Error EPCTrampolinePool::grow() {
- using namespace jitlink;
- assert(AvailableTrampolines.empty() &&
- "Grow called with trampolines still available");
- auto ResolverAddress = EPCIU.getResolverBlockAddress();
- assert(ResolverAddress && "Resolver address can not be null");
- auto &EPC = EPCIU.getExecutorProcessControl();
- auto PageSize = EPC.getPageSize();
- auto Alloc = SimpleSegmentAlloc::Create(
- EPC.getMemMgr(), nullptr,
- {{MemProt::Read | MemProt::Exec, {PageSize, Align(PageSize)}}});
- if (!Alloc)
- return Alloc.takeError();
- unsigned NumTrampolines = TrampolinesPerPage;
- auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
- EPCIU.getABISupport().writeTrampolines(SegInfo.WorkingMem.data(),
- SegInfo.Addr.getValue(),
- ResolverAddress, NumTrampolines);
- for (unsigned I = 0; I < NumTrampolines; ++I)
- AvailableTrampolines.push_back(SegInfo.Addr.getValue() +
- (I * TrampolineSize));
- auto FA = Alloc->finalize();
- if (!FA)
- return FA.takeError();
- TrampolineBlocks.push_back(std::move(*FA));
- return Error::success();
- }
- Error EPCIndirectStubsManager::createStub(StringRef StubName,
- JITTargetAddress StubAddr,
- JITSymbolFlags StubFlags) {
- StubInitsMap SIM;
- SIM[StubName] = std::make_pair(StubAddr, StubFlags);
- return createStubs(SIM);
- }
- Error EPCIndirectStubsManager::createStubs(const StubInitsMap &StubInits) {
- auto AvailableStubInfos = getIndirectStubs(EPCIU, StubInits.size());
- if (!AvailableStubInfos)
- return AvailableStubInfos.takeError();
- {
- std::lock_guard<std::mutex> Lock(ISMMutex);
- unsigned ASIdx = 0;
- for (auto &SI : StubInits) {
- auto &A = (*AvailableStubInfos)[ASIdx++];
- StubInfos[SI.first()] = std::make_pair(A, SI.second.second);
- }
- }
- auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
- switch (EPCIU.getABISupport().getPointerSize()) {
- case 4: {
- unsigned ASIdx = 0;
- std::vector<tpctypes::UInt32Write> PtrUpdates;
- for (auto &SI : StubInits)
- PtrUpdates.push_back(
- {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
- static_cast<uint32_t>(SI.second.first)});
- return MemAccess.writeUInt32s(PtrUpdates);
- }
- case 8: {
- unsigned ASIdx = 0;
- std::vector<tpctypes::UInt64Write> PtrUpdates;
- for (auto &SI : StubInits)
- PtrUpdates.push_back(
- {ExecutorAddr((*AvailableStubInfos)[ASIdx++].PointerAddress),
- static_cast<uint64_t>(SI.second.first)});
- return MemAccess.writeUInt64s(PtrUpdates);
- }
- default:
- return make_error<StringError>("Unsupported pointer size",
- inconvertibleErrorCode());
- }
- }
- JITEvaluatedSymbol EPCIndirectStubsManager::findStub(StringRef Name,
- bool ExportedStubsOnly) {
- std::lock_guard<std::mutex> Lock(ISMMutex);
- auto I = StubInfos.find(Name);
- if (I == StubInfos.end())
- return nullptr;
- return {I->second.first.StubAddress, I->second.second};
- }
- JITEvaluatedSymbol EPCIndirectStubsManager::findPointer(StringRef Name) {
- std::lock_guard<std::mutex> Lock(ISMMutex);
- auto I = StubInfos.find(Name);
- if (I == StubInfos.end())
- return nullptr;
- return {I->second.first.PointerAddress, I->second.second};
- }
- Error EPCIndirectStubsManager::updatePointer(StringRef Name,
- JITTargetAddress NewAddr) {
- JITTargetAddress PtrAddr = 0;
- {
- std::lock_guard<std::mutex> Lock(ISMMutex);
- auto I = StubInfos.find(Name);
- if (I == StubInfos.end())
- return make_error<StringError>("Unknown stub name",
- inconvertibleErrorCode());
- PtrAddr = I->second.first.PointerAddress;
- }
- auto &MemAccess = EPCIU.getExecutorProcessControl().getMemoryAccess();
- switch (EPCIU.getABISupport().getPointerSize()) {
- case 4: {
- tpctypes::UInt32Write PUpdate(ExecutorAddr(PtrAddr), NewAddr);
- return MemAccess.writeUInt32s(PUpdate);
- }
- case 8: {
- tpctypes::UInt64Write PUpdate(ExecutorAddr(PtrAddr), NewAddr);
- return MemAccess.writeUInt64s(PUpdate);
- }
- default:
- return make_error<StringError>("Unsupported pointer size",
- inconvertibleErrorCode());
- }
- }
- } // end anonymous namespace.
- namespace llvm {
- namespace orc {
- EPCIndirectionUtils::ABISupport::~ABISupport() {}
- Expected<std::unique_ptr<EPCIndirectionUtils>>
- EPCIndirectionUtils::Create(ExecutorProcessControl &EPC) {
- const auto &TT = EPC.getTargetTriple();
- switch (TT.getArch()) {
- default:
- return make_error<StringError>(
- std::string("No EPCIndirectionUtils available for ") + TT.str(),
- inconvertibleErrorCode());
- case Triple::aarch64:
- case Triple::aarch64_32:
- return CreateWithABI<OrcAArch64>(EPC);
- case Triple::x86:
- return CreateWithABI<OrcI386>(EPC);
- case Triple::mips:
- return CreateWithABI<OrcMips32Be>(EPC);
- case Triple::mipsel:
- return CreateWithABI<OrcMips32Le>(EPC);
- case Triple::mips64:
- case Triple::mips64el:
- return CreateWithABI<OrcMips64>(EPC);
- case Triple::x86_64:
- if (TT.getOS() == Triple::OSType::Win32)
- return CreateWithABI<OrcX86_64_Win32>(EPC);
- else
- return CreateWithABI<OrcX86_64_SysV>(EPC);
- }
- }
- Error EPCIndirectionUtils::cleanup() {
- auto &MemMgr = EPC.getMemMgr();
- auto Err = MemMgr.deallocate(std::move(IndirectStubAllocs));
- if (TP)
- Err = joinErrors(std::move(Err),
- static_cast<EPCTrampolinePool &>(*TP).deallocatePool());
- if (ResolverBlock)
- Err =
- joinErrors(std::move(Err), MemMgr.deallocate(std::move(ResolverBlock)));
- return Err;
- }
- Expected<JITTargetAddress>
- EPCIndirectionUtils::writeResolverBlock(JITTargetAddress ReentryFnAddr,
- JITTargetAddress ReentryCtxAddr) {
- using namespace jitlink;
- assert(ABI && "ABI can not be null");
- auto ResolverSize = ABI->getResolverCodeSize();
- auto Alloc =
- SimpleSegmentAlloc::Create(EPC.getMemMgr(), nullptr,
- {{MemProt::Read | MemProt::Exec,
- {ResolverSize, Align(EPC.getPageSize())}}});
- if (!Alloc)
- return Alloc.takeError();
- auto SegInfo = Alloc->getSegInfo(MemProt::Read | MemProt::Exec);
- ResolverBlockAddr = SegInfo.Addr.getValue();
- ABI->writeResolverCode(SegInfo.WorkingMem.data(), ResolverBlockAddr,
- ReentryFnAddr, ReentryCtxAddr);
- auto FA = Alloc->finalize();
- if (!FA)
- return FA.takeError();
- ResolverBlock = std::move(*FA);
- return ResolverBlockAddr;
- }
- std::unique_ptr<IndirectStubsManager>
- EPCIndirectionUtils::createIndirectStubsManager() {
- return std::make_unique<EPCIndirectStubsManager>(*this);
- }
- TrampolinePool &EPCIndirectionUtils::getTrampolinePool() {
- if (!TP)
- TP = std::make_unique<EPCTrampolinePool>(*this);
- return *TP;
- }
- LazyCallThroughManager &EPCIndirectionUtils::createLazyCallThroughManager(
- ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) {
- assert(!LCTM &&
- "createLazyCallThroughManager can not have been called before");
- LCTM = std::make_unique<LazyCallThroughManager>(ES, ErrorHandlerAddr,
- &getTrampolinePool());
- return *LCTM;
- }
- EPCIndirectionUtils::EPCIndirectionUtils(ExecutorProcessControl &EPC,
- std::unique_ptr<ABISupport> ABI)
- : EPC(EPC), ABI(std::move(ABI)) {
- assert(this->ABI && "ABI can not be null");
- assert(EPC.getPageSize() > getABISupport().getStubSize() &&
- "Stubs larger than one page are not supported");
- }
- Expected<EPCIndirectionUtils::IndirectStubInfoVector>
- EPCIndirectionUtils::getIndirectStubs(unsigned NumStubs) {
- using namespace jitlink;
- std::lock_guard<std::mutex> Lock(EPCUIMutex);
- // If there aren't enough stubs available then allocate some more.
- if (NumStubs > AvailableIndirectStubs.size()) {
- auto NumStubsToAllocate = NumStubs;
- auto PageSize = EPC.getPageSize();
- auto StubBytes = alignTo(NumStubsToAllocate * ABI->getStubSize(), PageSize);
- NumStubsToAllocate = StubBytes / ABI->getStubSize();
- auto PtrBytes =
- alignTo(NumStubsToAllocate * ABI->getPointerSize(), PageSize);
- auto StubProt = MemProt::Read | MemProt::Exec;
- auto PtrProt = MemProt::Read | MemProt::Write;
- auto Alloc = SimpleSegmentAlloc::Create(
- EPC.getMemMgr(), nullptr,
- {{StubProt, {static_cast<size_t>(StubBytes), Align(PageSize)}},
- {PtrProt, {static_cast<size_t>(PtrBytes), Align(PageSize)}}});
- if (!Alloc)
- return Alloc.takeError();
- auto StubSeg = Alloc->getSegInfo(StubProt);
- auto PtrSeg = Alloc->getSegInfo(PtrProt);
- ABI->writeIndirectStubsBlock(StubSeg.WorkingMem.data(),
- StubSeg.Addr.getValue(),
- PtrSeg.Addr.getValue(), NumStubsToAllocate);
- auto FA = Alloc->finalize();
- if (!FA)
- return FA.takeError();
- IndirectStubAllocs.push_back(std::move(*FA));
- auto StubExecutorAddr = StubSeg.Addr;
- auto PtrExecutorAddr = PtrSeg.Addr;
- for (unsigned I = 0; I != NumStubsToAllocate; ++I) {
- AvailableIndirectStubs.push_back(IndirectStubInfo(
- StubExecutorAddr.getValue(), PtrExecutorAddr.getValue()));
- StubExecutorAddr += ABI->getStubSize();
- PtrExecutorAddr += ABI->getPointerSize();
- }
- }
- assert(NumStubs <= AvailableIndirectStubs.size() &&
- "Sufficient stubs should have been allocated above");
- IndirectStubInfoVector Result;
- while (NumStubs--) {
- Result.push_back(AvailableIndirectStubs.back());
- AvailableIndirectStubs.pop_back();
- }
- return std::move(Result);
- }
- static JITTargetAddress reentry(JITTargetAddress LCTMAddr,
- JITTargetAddress TrampolineAddr) {
- auto &LCTM = *jitTargetAddressToPointer<LazyCallThroughManager *>(LCTMAddr);
- std::promise<JITTargetAddress> LandingAddrP;
- auto LandingAddrF = LandingAddrP.get_future();
- LCTM.resolveTrampolineLandingAddress(
- TrampolineAddr,
- [&](JITTargetAddress Addr) { LandingAddrP.set_value(Addr); });
- return LandingAddrF.get();
- }
- Error setUpInProcessLCTMReentryViaEPCIU(EPCIndirectionUtils &EPCIU) {
- auto &LCTM = EPCIU.getLazyCallThroughManager();
- return EPCIU
- .writeResolverBlock(pointerToJITTargetAddress(&reentry),
- pointerToJITTargetAddress(&LCTM))
- .takeError();
- }
- } // end namespace orc
- } // end namespace llvm
|