235 lines
8.3 KiB
C++
235 lines
8.3 KiB
C++
|
//===---------- 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 {
|
||
|
|
||
|
LazyCallThroughManager::LazyCallThroughManager(
|
||
|
ExecutionSession &ES, JITTargetAddress ErrorHandlerAddr, TrampolinePool *TP)
|
||
|
: ES(ES), ErrorHandlerAddr(ErrorHandlerAddr), TP(TP) {}
|
||
|
|
||
|
Expected<JITTargetAddress> LazyCallThroughManager::getCallThroughTrampoline(
|
||
|
JITDylib &SourceJD, SymbolStringPtr SymbolName,
|
||
|
NotifyResolvedFunction NotifyResolved) {
|
||
|
assert(TP && "TrampolinePool not set");
|
||
|
|
||
|
std::lock_guard<std::mutex> Lock(LCTMMutex);
|
||
|
auto Trampoline = TP->getTrampoline();
|
||
|
|
||
|
if (!Trampoline)
|
||
|
return Trampoline.takeError();
|
||
|
|
||
|
Reexports[*Trampoline] = ReexportsEntry{&SourceJD, std::move(SymbolName)};
|
||
|
Notifiers[*Trampoline] = std::move(NotifyResolved);
|
||
|
return *Trampoline;
|
||
|
}
|
||
|
|
||
|
JITTargetAddress LazyCallThroughManager::reportCallThroughError(Error Err) {
|
||
|
ES.reportError(std::move(Err));
|
||
|
return ErrorHandlerAddr;
|
||
|
}
|
||
|
|
||
|
Expected<LazyCallThroughManager::ReexportsEntry>
|
||
|
LazyCallThroughManager::findReexport(JITTargetAddress TrampolineAddr) {
|
||
|
std::lock_guard<std::mutex> Lock(LCTMMutex);
|
||
|
auto I = Reexports.find(TrampolineAddr);
|
||
|
if (I == Reexports.end())
|
||
|
return createStringError(inconvertibleErrorCode(),
|
||
|
"Missing reexport for trampoline address %p",
|
||
|
TrampolineAddr);
|
||
|
return I->second;
|
||
|
}
|
||
|
|
||
|
Error LazyCallThroughManager::notifyResolved(JITTargetAddress TrampolineAddr,
|
||
|
JITTargetAddress ResolvedAddr) {
|
||
|
NotifyResolvedFunction NotifyResolved;
|
||
|
{
|
||
|
std::lock_guard<std::mutex> Lock(LCTMMutex);
|
||
|
auto I = Notifiers.find(TrampolineAddr);
|
||
|
if (I != Notifiers.end()) {
|
||
|
NotifyResolved = std::move(I->second);
|
||
|
Notifiers.erase(I);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NotifyResolved ? NotifyResolved(ResolvedAddr) : Error::success();
|
||
|
}
|
||
|
|
||
|
void LazyCallThroughManager::resolveTrampolineLandingAddress(
|
||
|
JITTargetAddress TrampolineAddr,
|
||
|
NotifyLandingResolvedFunction NotifyLandingResolved) {
|
||
|
|
||
|
auto Entry = findReexport(TrampolineAddr);
|
||
|
if (!Entry)
|
||
|
return NotifyLandingResolved(reportCallThroughError(Entry.takeError()));
|
||
|
|
||
|
// Declaring SLS and the callback outside of the call to ES.lookup is a
|
||
|
// workaround to fix build failures on AIX and on z/OS platforms.
|
||
|
SymbolLookupSet SLS({Entry->SymbolName});
|
||
|
auto Callback = [this, TrampolineAddr, SymbolName = Entry->SymbolName,
|
||
|
NotifyLandingResolved = std::move(NotifyLandingResolved)](
|
||
|
Expected<SymbolMap> Result) mutable {
|
||
|
if (Result) {
|
||
|
assert(Result->size() == 1 && "Unexpected result size");
|
||
|
assert(Result->count(SymbolName) && "Unexpected result value");
|
||
|
JITTargetAddress LandingAddr = (*Result)[SymbolName].getAddress();
|
||
|
|
||
|
if (auto Err = notifyResolved(TrampolineAddr, LandingAddr))
|
||
|
NotifyLandingResolved(reportCallThroughError(std::move(Err)));
|
||
|
else
|
||
|
NotifyLandingResolved(LandingAddr);
|
||
|
} else {
|
||
|
NotifyLandingResolved(reportCallThroughError(Result.takeError()));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
ES.lookup(LookupKind::Static,
|
||
|
makeJITDylibSearchOrder(Entry->SourceJD,
|
||
|
JITDylibLookupFlags::MatchAllSymbols),
|
||
|
std::move(SLS), SymbolState::Ready, std::move(Callback),
|
||
|
NoDependenciesToRegister);
|
||
|
}
|
||
|
|
||
|
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:
|
||
|
case Triple::aarch64_32:
|
||
|
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, ImplSymbolMap *SrcJDLoc)
|
||
|
: MaterializationUnit(extractFlags(CallableAliases), nullptr),
|
||
|
LCTManager(LCTManager), ISManager(ISManager), SourceJD(SourceJD),
|
||
|
CallableAliases(std::move(CallableAliases)), AliaseeTable(SrcJDLoc) {}
|
||
|
|
||
|
StringRef LazyReexportsMaterializationUnit::getName() const {
|
||
|
return "<Lazy Reexports>";
|
||
|
}
|
||
|
|
||
|
void LazyReexportsMaterializationUnit::materialize(
|
||
|
std::unique_ptr<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())
|
||
|
if (auto Err = R->replace(lazyReexports(LCTManager, ISManager, SourceJD,
|
||
|
std::move(CallableAliases),
|
||
|
AliaseeTable))) {
|
||
|
R->getExecutionSession().reportError(std::move(Err));
|
||
|
R->failMaterialization();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
IndirectStubsManager::StubInitsMap StubInits;
|
||
|
for (auto &Alias : RequestedAliases) {
|
||
|
|
||
|
auto CallThroughTrampoline = LCTManager.getCallThroughTrampoline(
|
||
|
SourceJD, Alias.second.Aliasee,
|
||
|
[&ISManager = this->ISManager,
|
||
|
StubSym = Alias.first](JITTargetAddress ResolvedAddr) -> Error {
|
||
|
return ISManager.updatePointer(*StubSym, ResolvedAddr);
|
||
|
});
|
||
|
|
||
|
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.
|