mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
65d983e2c9
So far we had no way to distinguish between JITLink and RuntimeDyld in lli. Instead, we used implicit knowledge that RuntimeDyld would be used for linking ELF. In order to get D97337 to work with lli though, we have to move on and allow JITLink for ELF. This patch uses extensible RTTI to allow external clients to add their own layers without touching the LLVM sources. Reviewed By: lhames Differential Revision: https://reviews.llvm.org/D97338
356 lines
11 KiB
C++
356 lines
11 KiB
C++
//===-- RTDyldObjectLinkingLayer.cpp - RuntimeDyld backed ORC ObjectLayer -===//
|
|
//
|
|
// 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/RTDyldObjectLinkingLayer.h"
|
|
#include "llvm/Object/COFF.h"
|
|
|
|
namespace {
|
|
|
|
using namespace llvm;
|
|
using namespace llvm::orc;
|
|
|
|
class JITDylibSearchOrderResolver : public JITSymbolResolver {
|
|
public:
|
|
JITDylibSearchOrderResolver(MaterializationResponsibility &MR) : MR(MR) {}
|
|
|
|
void lookup(const LookupSet &Symbols, OnResolvedFunction OnResolved) override {
|
|
auto &ES = MR.getTargetJITDylib().getExecutionSession();
|
|
SymbolLookupSet InternedSymbols;
|
|
|
|
// Intern the requested symbols: lookup takes interned strings.
|
|
for (auto &S : Symbols)
|
|
InternedSymbols.add(ES.intern(S));
|
|
|
|
// Build an OnResolve callback to unwrap the interned strings and pass them
|
|
// to the OnResolved callback.
|
|
auto OnResolvedWithUnwrap =
|
|
[OnResolved = std::move(OnResolved)](
|
|
Expected<SymbolMap> InternedResult) mutable {
|
|
if (!InternedResult) {
|
|
OnResolved(InternedResult.takeError());
|
|
return;
|
|
}
|
|
|
|
LookupResult Result;
|
|
for (auto &KV : *InternedResult)
|
|
Result[*KV.first] = std::move(KV.second);
|
|
OnResolved(Result);
|
|
};
|
|
|
|
// Register dependencies for all symbols contained in this set.
|
|
auto RegisterDependencies = [&](const SymbolDependenceMap &Deps) {
|
|
MR.addDependenciesForAll(Deps);
|
|
};
|
|
|
|
JITDylibSearchOrder LinkOrder;
|
|
MR.getTargetJITDylib().withLinkOrderDo(
|
|
[&](const JITDylibSearchOrder &LO) { LinkOrder = LO; });
|
|
ES.lookup(LookupKind::Static, LinkOrder, InternedSymbols,
|
|
SymbolState::Resolved, std::move(OnResolvedWithUnwrap),
|
|
RegisterDependencies);
|
|
}
|
|
|
|
Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override {
|
|
LookupSet Result;
|
|
|
|
for (auto &KV : MR.getSymbols()) {
|
|
if (Symbols.count(*KV.first))
|
|
Result.insert(*KV.first);
|
|
}
|
|
|
|
return Result;
|
|
}
|
|
|
|
private:
|
|
MaterializationResponsibility &MR;
|
|
};
|
|
|
|
} // end anonymous namespace
|
|
|
|
namespace llvm {
|
|
namespace orc {
|
|
|
|
char RTDyldObjectLinkingLayer::ID;
|
|
|
|
using BaseT = RTTIExtends<RTDyldObjectLinkingLayer, ObjectLayer>;
|
|
|
|
RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer(
|
|
ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager)
|
|
: BaseT(ES), GetMemoryManager(GetMemoryManager) {
|
|
ES.registerResourceManager(*this);
|
|
}
|
|
|
|
RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() {
|
|
assert(MemMgrs.empty() && "Layer destroyed with resources still attached");
|
|
}
|
|
|
|
void RTDyldObjectLinkingLayer::emit(
|
|
std::unique_ptr<MaterializationResponsibility> R,
|
|
std::unique_ptr<MemoryBuffer> O) {
|
|
assert(O && "Object must not be null");
|
|
|
|
auto &ES = getExecutionSession();
|
|
|
|
auto Obj = object::ObjectFile::createObjectFile(*O);
|
|
|
|
if (!Obj) {
|
|
getExecutionSession().reportError(Obj.takeError());
|
|
R->failMaterialization();
|
|
return;
|
|
}
|
|
|
|
// Collect the internal symbols from the object file: We will need to
|
|
// filter these later.
|
|
auto InternalSymbols = std::make_shared<std::set<StringRef>>();
|
|
{
|
|
for (auto &Sym : (*Obj)->symbols()) {
|
|
|
|
// Skip file symbols.
|
|
if (auto SymType = Sym.getType()) {
|
|
if (*SymType == object::SymbolRef::ST_File)
|
|
continue;
|
|
} else {
|
|
ES.reportError(SymType.takeError());
|
|
R->failMaterialization();
|
|
return;
|
|
}
|
|
|
|
Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();
|
|
if (!SymFlagsOrErr) {
|
|
// TODO: Test this error.
|
|
ES.reportError(SymFlagsOrErr.takeError());
|
|
R->failMaterialization();
|
|
return;
|
|
}
|
|
|
|
// Don't include symbols that aren't global.
|
|
if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) {
|
|
if (auto SymName = Sym.getName())
|
|
InternalSymbols->insert(*SymName);
|
|
else {
|
|
ES.reportError(SymName.takeError());
|
|
R->failMaterialization();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
auto MemMgr = GetMemoryManager();
|
|
auto &MemMgrRef = *MemMgr;
|
|
|
|
// Switch to shared ownership of MR so that it can be captured by both
|
|
// lambdas below.
|
|
std::shared_ptr<MaterializationResponsibility> SharedR(std::move(R));
|
|
|
|
JITDylibSearchOrderResolver Resolver(*SharedR);
|
|
|
|
jitLinkForORC(
|
|
object::OwningBinary<object::ObjectFile>(std::move(*Obj), std::move(O)),
|
|
MemMgrRef, Resolver, ProcessAllSections,
|
|
[this, SharedR, &MemMgrRef, InternalSymbols](
|
|
const object::ObjectFile &Obj,
|
|
RuntimeDyld::LoadedObjectInfo &LoadedObjInfo,
|
|
std::map<StringRef, JITEvaluatedSymbol> ResolvedSymbols) {
|
|
return onObjLoad(*SharedR, Obj, MemMgrRef, LoadedObjInfo,
|
|
ResolvedSymbols, *InternalSymbols);
|
|
},
|
|
[this, SharedR, MemMgr = std::move(MemMgr)](
|
|
object::OwningBinary<object::ObjectFile> Obj,
|
|
std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,
|
|
Error Err) mutable {
|
|
onObjEmit(*SharedR, std::move(Obj), std::move(MemMgr),
|
|
std::move(LoadedObjInfo), std::move(Err));
|
|
});
|
|
}
|
|
|
|
void RTDyldObjectLinkingLayer::registerJITEventListener(JITEventListener &L) {
|
|
std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
|
|
assert(!llvm::is_contained(EventListeners, &L) &&
|
|
"Listener has already been registered");
|
|
EventListeners.push_back(&L);
|
|
}
|
|
|
|
void RTDyldObjectLinkingLayer::unregisterJITEventListener(JITEventListener &L) {
|
|
std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
|
|
auto I = llvm::find(EventListeners, &L);
|
|
assert(I != EventListeners.end() && "Listener not registered");
|
|
EventListeners.erase(I);
|
|
}
|
|
|
|
Error RTDyldObjectLinkingLayer::onObjLoad(
|
|
MaterializationResponsibility &R, const object::ObjectFile &Obj,
|
|
RuntimeDyld::MemoryManager &MemMgr,
|
|
RuntimeDyld::LoadedObjectInfo &LoadedObjInfo,
|
|
std::map<StringRef, JITEvaluatedSymbol> Resolved,
|
|
std::set<StringRef> &InternalSymbols) {
|
|
SymbolFlagsMap ExtraSymbolsToClaim;
|
|
SymbolMap Symbols;
|
|
|
|
// Hack to support COFF constant pool comdats introduced during compilation:
|
|
// (See http://llvm.org/PR40074)
|
|
if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(&Obj)) {
|
|
auto &ES = getExecutionSession();
|
|
|
|
// For all resolved symbols that are not already in the responsibilty set:
|
|
// check whether the symbol is in a comdat section and if so mark it as
|
|
// weak.
|
|
for (auto &Sym : COFFObj->symbols()) {
|
|
// getFlags() on COFF symbols can't fail.
|
|
uint32_t SymFlags = cantFail(Sym.getFlags());
|
|
if (SymFlags & object::BasicSymbolRef::SF_Undefined)
|
|
continue;
|
|
auto Name = Sym.getName();
|
|
if (!Name)
|
|
return Name.takeError();
|
|
auto I = Resolved.find(*Name);
|
|
|
|
// Skip unresolved symbols, internal symbols, and symbols that are
|
|
// already in the responsibility set.
|
|
if (I == Resolved.end() || InternalSymbols.count(*Name) ||
|
|
R.getSymbols().count(ES.intern(*Name)))
|
|
continue;
|
|
auto Sec = Sym.getSection();
|
|
if (!Sec)
|
|
return Sec.takeError();
|
|
if (*Sec == COFFObj->section_end())
|
|
continue;
|
|
auto &COFFSec = *COFFObj->getCOFFSection(**Sec);
|
|
if (COFFSec.Characteristics & COFF::IMAGE_SCN_LNK_COMDAT)
|
|
I->second.setFlags(I->second.getFlags() | JITSymbolFlags::Weak);
|
|
}
|
|
}
|
|
|
|
for (auto &KV : Resolved) {
|
|
// Scan the symbols and add them to the Symbols map for resolution.
|
|
|
|
// We never claim internal symbols.
|
|
if (InternalSymbols.count(KV.first))
|
|
continue;
|
|
|
|
auto InternedName = getExecutionSession().intern(KV.first);
|
|
auto Flags = KV.second.getFlags();
|
|
|
|
// Override object flags and claim responsibility for symbols if
|
|
// requested.
|
|
if (OverrideObjectFlags || AutoClaimObjectSymbols) {
|
|
auto I = R.getSymbols().find(InternedName);
|
|
|
|
if (OverrideObjectFlags && I != R.getSymbols().end())
|
|
Flags = I->second;
|
|
else if (AutoClaimObjectSymbols && I == R.getSymbols().end())
|
|
ExtraSymbolsToClaim[InternedName] = Flags;
|
|
}
|
|
|
|
Symbols[InternedName] = JITEvaluatedSymbol(KV.second.getAddress(), Flags);
|
|
}
|
|
|
|
if (!ExtraSymbolsToClaim.empty()) {
|
|
if (auto Err = R.defineMaterializing(ExtraSymbolsToClaim))
|
|
return Err;
|
|
|
|
// If we claimed responsibility for any weak symbols but were rejected then
|
|
// we need to remove them from the resolved set.
|
|
for (auto &KV : ExtraSymbolsToClaim)
|
|
if (KV.second.isWeak() && !R.getSymbols().count(KV.first))
|
|
Symbols.erase(KV.first);
|
|
}
|
|
|
|
if (auto Err = R.notifyResolved(Symbols)) {
|
|
R.failMaterialization();
|
|
return Err;
|
|
}
|
|
|
|
if (NotifyLoaded)
|
|
NotifyLoaded(R, Obj, LoadedObjInfo);
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
void RTDyldObjectLinkingLayer::onObjEmit(
|
|
MaterializationResponsibility &R,
|
|
object::OwningBinary<object::ObjectFile> O,
|
|
std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr,
|
|
std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo, Error Err) {
|
|
if (Err) {
|
|
getExecutionSession().reportError(std::move(Err));
|
|
R.failMaterialization();
|
|
return;
|
|
}
|
|
|
|
if (auto Err = R.notifyEmitted()) {
|
|
getExecutionSession().reportError(std::move(Err));
|
|
R.failMaterialization();
|
|
return;
|
|
}
|
|
|
|
std::unique_ptr<object::ObjectFile> Obj;
|
|
std::unique_ptr<MemoryBuffer> ObjBuffer;
|
|
std::tie(Obj, ObjBuffer) = O.takeBinary();
|
|
|
|
// Run EventListener notifyLoaded callbacks.
|
|
{
|
|
std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
|
|
for (auto *L : EventListeners)
|
|
L->notifyObjectLoaded(pointerToJITTargetAddress(MemMgr.get()), *Obj,
|
|
*LoadedObjInfo);
|
|
}
|
|
|
|
if (NotifyEmitted)
|
|
NotifyEmitted(R, std::move(ObjBuffer));
|
|
|
|
if (auto Err = R.withResourceKeyDo(
|
|
[&](ResourceKey K) { MemMgrs[K].push_back(std::move(MemMgr)); })) {
|
|
getExecutionSession().reportError(std::move(Err));
|
|
R.failMaterialization();
|
|
}
|
|
}
|
|
|
|
Error RTDyldObjectLinkingLayer::handleRemoveResources(ResourceKey K) {
|
|
|
|
std::vector<MemoryManagerUP> MemMgrsToRemove;
|
|
|
|
getExecutionSession().runSessionLocked([&] {
|
|
auto I = MemMgrs.find(K);
|
|
if (I != MemMgrs.end()) {
|
|
std::swap(MemMgrsToRemove, I->second);
|
|
MemMgrs.erase(I);
|
|
}
|
|
});
|
|
|
|
{
|
|
std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);
|
|
for (auto &MemMgr : MemMgrsToRemove) {
|
|
for (auto *L : EventListeners)
|
|
L->notifyFreeingObject(pointerToJITTargetAddress(MemMgr.get()));
|
|
MemMgr->deregisterEHFrames();
|
|
}
|
|
}
|
|
|
|
return Error::success();
|
|
}
|
|
|
|
void RTDyldObjectLinkingLayer::handleTransferResources(ResourceKey DstKey,
|
|
ResourceKey SrcKey) {
|
|
auto I = MemMgrs.find(SrcKey);
|
|
if (I != MemMgrs.end()) {
|
|
auto &SrcMemMgrs = I->second;
|
|
auto &DstMemMgrs = MemMgrs[DstKey];
|
|
DstMemMgrs.reserve(DstMemMgrs.size() + SrcMemMgrs.size());
|
|
for (auto &MemMgr : SrcMemMgrs)
|
|
DstMemMgrs.push_back(std::move(MemMgr));
|
|
|
|
// Erase SrcKey entry using value rather than iterator I: I may have been
|
|
// invalidated when we looked up DstKey.
|
|
MemMgrs.erase(SrcKey);
|
|
}
|
|
}
|
|
|
|
} // End namespace orc.
|
|
} // End namespace llvm.
|