Fix "JIT session error: Symbols not found: [ DW.ref.__gxx_personality_v0 ] error" which happens when trying to use exceptions on ppc linux. To do this, it expands AutoClaimSymbols option in RTDyldObjectLinkingLayer to also claim weak symbols before they are tried to be resovled. In ppc linux, DW.ref symbols is emitted as weak hidden symbols in the later stage of MC pipeline. This means when using IRLayer (i.e. LLJIT), IRLayer will not claim responsibility for such symbols and RuntimeDyld will skip defining this symbol even though it couldn't resolve corresponding external symbol. Reviewed By: sgraenitz Differential Revision: https://reviews.llvm.org/D129175
391 lines
12 KiB
C++
391 lines
12 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>>();
|
|
{
|
|
SymbolFlagsMap ExtraSymbolsToClaim;
|
|
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;
|
|
}
|
|
|
|
// Try to claim responsibility of weak symbols
|
|
// if AutoClaimObjectSymbols flag is set.
|
|
if (AutoClaimObjectSymbols &&
|
|
(*SymFlagsOrErr & object::BasicSymbolRef::SF_Weak)) {
|
|
auto SymName = Sym.getName();
|
|
if (!SymName) {
|
|
ES.reportError(SymName.takeError());
|
|
R->failMaterialization();
|
|
return;
|
|
}
|
|
|
|
// Already included in responsibility set, skip it
|
|
SymbolStringPtr SymbolName = ES.intern(*SymName);
|
|
if (R->getSymbols().count(SymbolName))
|
|
continue;
|
|
|
|
auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);
|
|
if (!SymFlags) {
|
|
ES.reportError(SymFlags.takeError());
|
|
R->failMaterialization();
|
|
return;
|
|
}
|
|
|
|
ExtraSymbolsToClaim[SymbolName] = *SymFlags;
|
|
continue;
|
|
}
|
|
|
|
// 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;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!ExtraSymbolsToClaim.empty()) {
|
|
if (auto Err = R->defineMaterializing(ExtraSymbolsToClaim)) {
|
|
ES.reportError(std::move(Err));
|
|
R->failMaterialization();
|
|
}
|
|
}
|
|
}
|
|
|
|
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.
|