| //===---------- 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<TrampolinePool> TP) |
| : ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(std::move(TP)) {} |
| |
| Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline( |
| JITDylib &SourceJD, SymbolStringPtr SymbolName, |
| std::shared_ptr<NotifyResolvedFunction> NotifyResolved) { |
| std::lock_guard<std::mutex> 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<std::mutex> 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(JITDylibSearchList({{SourceJD, true}}), SymbolName); |
| |
| if (!LookupResult) { |
| ES.reportError(LookupResult.takeError()); |
| return ErrorHandlerAddr; |
| } |
| |
| auto ResolvedAddr = LookupResult->getAddress(); |
| |
| std::shared_ptr<NotifyResolvedFunction> NotifyResolved = nullptr; |
| { |
| std::lock_guard<std::mutex> 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<std::unique_ptr<LazyCallThroughManager>> |
| createLocalLazyCallThroughManager(const Triple &T, ExecutionSession &ES, |
| JITTargetAddress ErrorHandlerAddr) { |
| switch (T.getArch()) { |
| default: |
| return make_error<StringError>( |
| std::string("No callback manager available for ") + T.str(), |
| inconvertibleErrorCode()); |
| |
| case Triple::aarch64: |
| return LocalLazyCallThroughManager::Create<OrcAArch64>(ES, |
| ErrorHandlerAddr); |
| |
| case Triple::x86: |
| return LocalLazyCallThroughManager::Create<OrcI386>(ES, ErrorHandlerAddr); |
| |
| case Triple::mips: |
| return LocalLazyCallThroughManager::Create<OrcMips32Be>(ES, |
| ErrorHandlerAddr); |
| |
| case Triple::mipsel: |
| return LocalLazyCallThroughManager::Create<OrcMips32Le>(ES, |
| ErrorHandlerAddr); |
| |
| case Triple::mips64: |
| case Triple::mips64el: |
| return LocalLazyCallThroughManager::Create<OrcMips64>(ES, ErrorHandlerAddr); |
| |
| case Triple::x86_64: |
| if (T.getOS() == Triple::OSType::Win32) |
| return LocalLazyCallThroughManager::Create<OrcX86_64_Win32>( |
| ES, ErrorHandlerAddr); |
| else |
| return LocalLazyCallThroughManager::Create<OrcX86_64_SysV>( |
| ES, ErrorHandlerAddr); |
| } |
| } |
| |
| LazyReexportsMaterializationUnit::LazyReexportsMaterializationUnit( |
| LazyCallThroughManager &LCTManager, IndirectStubsManager &ISManager, |
| JITDylib &SourceJD, SymbolAliasMap CallableAliases, 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); |
| })) {} |
| |
| StringRef LazyReexportsMaterializationUnit::getName() const { |
| return "<Lazy Reexports>"; |
| } |
| |
| 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))); |
| |
| 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 (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); |
| |
| R.notifyResolved(Stubs); |
| 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. |