//===---------- LazyReexports.cpp - Utilities for lazy reexports ----------===// // // 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/LazyReexports.h" #include "llvm/ADT/Triple.h" #include "llvm/ExecutionEngine/Orc/OrcABISupport.h" #define DEBUG_TYPE "orc" namespace llvm { namespace orc { void LazyCallThroughManager::NotifyResolvedFunction::anchor() {} LazyCallThroughManager::LazyCallThroughManager( ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, std::unique_ptr TP) : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(std::move(TP)) {} Expected LazyCallThroughManager::getCallThroughTrampoline( JITDylib &SourceJD, SymbolStringPtr SymbolName, std::shared_ptr NotifyResolved) { std::lock_guard Lock(LCTMMutex); auto Trampoline = TP->getTrampoline(); if (!Trampoline) return Trampoline.takeError(); Reexports[*Trampoline] = std::make_pair(&SourceJD, std::move(SymbolName)); Notifiers[*Trampoline] = std::move(NotifyResolved); return *Trampoline; } JITTargetAddress LazyCallThroughManager::callThroughToSymbol(JITTargetAddress TrampolineAddr) { JITDylib *SourceJD = nullptr; SymbolStringPtr SymbolName; { std::lock_guard Lock(LCTMMutex); auto I = Reexports.find(TrampolineAddr); if (I == Reexports.end()) return ErrorHandlerAddr; SourceJD = I->second.first; SymbolName = I->second.second; } auto LookupResult = ES.lookup( makeJITDylibSearchOrder(SourceJD, JITDylibLookupFlags::MatchAllSymbols), SymbolName); if (!LookupResult) { ES.reportError(LookupResult.takeError()); return ErrorHandlerAddr; } auto ResolvedAddr = LookupResult->getAddress(); std::shared_ptr NotifyResolved = nullptr; { std::lock_guard Lock(LCTMMutex); auto I = Notifiers.find(TrampolineAddr); if (I != Notifiers.end()) { NotifyResolved = I->second; Notifiers.erase(I); } } if (NotifyResolved) { if (auto Err = (*NotifyResolved)(*SourceJD, SymbolName, ResolvedAddr)) { ES.reportError(std::move(Err)); return ErrorHandlerAddr; } } return ResolvedAddr; } Expected> createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr) { switch (T.getArch()) { default: return make_error( std::string("No callback manager available for ") + T.str(), inconvertibleErrorCode()); case Triple::aarch64: case Triple::aarch64_32: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::x86: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::mips: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::mipsel: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::mips64: case Triple::mips64el: return LocalLazyCallThroughManager::Create(ES, ErrorHandlerAddr); case Triple::x86_64: if (T.getOS() == Triple::OSType::Win32) return LocalLazyCallThroughManager::Create( ES, ErrorHandlerAddr); else return LocalLazyCallThroughManager::Create( ES, ErrorHandlerAddr); } } LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit( LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, JITDylib &SourceJD, SymbolAliasMap CallableAliases, ImplSymbolMap *SrcJDLoc, VModuleKey K) : MaterializationUnit(extractFlags(CallableAliases), std::move(K)), LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD), CallableAliases(std::move(CallableAliases)), NotifyResolved(LazyCallThroughManager::createNotifyResolvedFunction( [&ISManager](JITDylib &JD, const SymbolStringPtr &SymbolName, JITTargetAddress ResolvedAddr) { return ISManager.updatePointer(*SymbolName, ResolvedAddr); })), AliaseeTable(SrcJDLoc) {} StringRef LazyReexportsMaterializationUnit::getName() const { return ""; } void LazyReexportsMaterializationUnit::materialize( MaterializationResponsibility R) { auto RequestedSymbols = R.getRequestedSymbols(); SymbolAliasMap RequestedAliases; for (auto &RequestedSymbol : RequestedSymbols) { auto I = CallableAliases.find(RequestedSymbol); assert(I != CallableAliases.end() && "Symbol not found in alias map?"); RequestedAliases[I->first] = std::move(I->second); CallableAliases.erase(I); } if (!CallableAliases.empty()) R.replace(lazyReexports(LCTManager, ISManager, SourceJD, std::move(CallableAliases), AliaseeTable)); IndirectStubsManager::StubInitsMap StubInits; for (auto &Alias : RequestedAliases) { auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline( SourceJD, Alias.second.Aliasee, NotifyResolved); if (!CallThroughTrampoline) { SourceJD.getExecutionSession().reportError( CallThroughTrampoline.takeError()); R.failMaterialization(); return; } StubInits[*Alias.first] = std::make_pair(*CallThroughTrampoline, Alias.second.AliasFlags); } if (AliaseeTable != nullptr && !RequestedAliases.empty()) AliaseeTable->trackImpls(RequestedAliases, &SourceJD); if (auto Err = ISManager.createStubs(StubInits)) { SourceJD.getExecutionSession().reportError(std::move(Err)); R.failMaterialization(); return; } SymbolMap Stubs; for (auto &Alias : RequestedAliases) Stubs[Alias.first] = ISManager.findStub(*Alias.first, false); // No registered dependencies, so these calls cannot fail. cantFail(R.notifyResolved(Stubs)); cantFail(R.notifyEmitted()); } void LazyReexportsMaterializationUnit::discard(const JITDylib &JD, const SymbolStringPtr &Name) { assert(CallableAliases.count(Name) && "Symbol not covered by this MaterializationUnit"); CallableAliases.erase(Name); } SymbolFlagsMap LazyReexportsMaterializationUnit::extractFlags(const SymbolAliasMap &Aliases) { SymbolFlagsMap SymbolFlags; for (auto &KV : Aliases) { assert(KV.second.AliasFlags.isCallable() && "Lazy re-exports must be callable symbols"); SymbolFlags[KV.first] = KV.second.AliasFlags; } return SymbolFlags; } } // End namespace orc. } // End namespace llvm.