452 lines · cpp
1//===-- RTDyldObjectLinkingLayer.cpp - RuntimeDyld backed ORC ObjectLayer -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include <memory>10 11#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"12#include "llvm/Object/COFF.h"13 14namespace {15 16using namespace llvm;17using namespace llvm::orc;18 19class JITDylibSearchOrderResolver : public JITSymbolResolver {20public:21 JITDylibSearchOrderResolver(MaterializationResponsibility &MR,22 SymbolDependenceMap &Deps)23 : MR(MR), Deps(Deps) {}24 25 void lookup(const LookupSet &Symbols,26 OnResolvedFunction OnResolved) override {27 auto &ES = MR.getTargetJITDylib().getExecutionSession();28 SymbolLookupSet InternedSymbols;29 30 // Intern the requested symbols: lookup takes interned strings.31 for (auto &S : Symbols)32 InternedSymbols.add(ES.intern(S));33 34 // Build an OnResolve callback to unwrap the interned strings and pass them35 // to the OnResolved callback.36 auto OnResolvedWithUnwrap =37 [OnResolved = std::move(OnResolved)](38 Expected<SymbolMap> InternedResult) mutable {39 if (!InternedResult) {40 OnResolved(InternedResult.takeError());41 return;42 }43 44 LookupResult Result;45 for (auto &KV : *InternedResult)46 Result[*KV.first] = {KV.second.getAddress().getValue(),47 KV.second.getFlags()};48 OnResolved(Result);49 };50 51 JITDylibSearchOrder LinkOrder;52 MR.getTargetJITDylib().withLinkOrderDo(53 [&](const JITDylibSearchOrder &LO) { LinkOrder = LO; });54 ES.lookup(55 LookupKind::Static, LinkOrder, InternedSymbols, SymbolState::Resolved,56 std::move(OnResolvedWithUnwrap),57 [this](const SymbolDependenceMap &LookupDeps) { Deps = LookupDeps; });58 }59 60 Expected<LookupSet> getResponsibilitySet(const LookupSet &Symbols) override {61 LookupSet Result;62 63 for (auto &KV : MR.getSymbols()) {64 if (Symbols.count(*KV.first))65 Result.insert(*KV.first);66 }67 68 return Result;69 }70 71private:72 MaterializationResponsibility &MR;73 SymbolDependenceMap &Deps;74};75 76} // end anonymous namespace77 78namespace llvm {79namespace orc {80 81char RTDyldObjectLinkingLayer::ID;82 83using BaseT = RTTIExtends<RTDyldObjectLinkingLayer, ObjectLayer>;84 85RTDyldObjectLinkingLayer::RTDyldObjectLinkingLayer(86 ExecutionSession &ES, GetMemoryManagerFunction GetMemoryManager)87 : BaseT(ES), GetMemoryManager(std::move(GetMemoryManager)) {88 ES.registerResourceManager(*this);89}90 91RTDyldObjectLinkingLayer::~RTDyldObjectLinkingLayer() {92 assert(MemMgrs.empty() &&93 "Layer destroyed with resources still attached"94 "(ExecutionSession::endSession() must be called prior to "95 "destruction)");96}97 98void RTDyldObjectLinkingLayer::emit(99 std::unique_ptr<MaterializationResponsibility> R,100 std::unique_ptr<MemoryBuffer> O) {101 assert(O && "Object must not be null");102 103 auto &ES = getExecutionSession();104 105 auto Obj = object::ObjectFile::createObjectFile(*O);106 107 if (!Obj) {108 getExecutionSession().reportError(Obj.takeError());109 R->failMaterialization();110 return;111 }112 113 // Collect the internal symbols from the object file: We will need to114 // filter these later.115 auto InternalSymbols = std::make_shared<std::set<StringRef>>();116 {117 SymbolFlagsMap ExtraSymbolsToClaim;118 for (auto &Sym : (*Obj)->symbols()) {119 120 // Skip file symbols.121 if (auto SymType = Sym.getType()) {122 if (*SymType == object::SymbolRef::ST_File)123 continue;124 } else {125 ES.reportError(SymType.takeError());126 R->failMaterialization();127 return;128 }129 130 Expected<uint32_t> SymFlagsOrErr = Sym.getFlags();131 if (!SymFlagsOrErr) {132 // TODO: Test this error.133 ES.reportError(SymFlagsOrErr.takeError());134 R->failMaterialization();135 return;136 }137 138 // Try to claim responsibility of weak symbols139 // if AutoClaimObjectSymbols flag is set.140 if (AutoClaimObjectSymbols &&141 (*SymFlagsOrErr & object::BasicSymbolRef::SF_Weak)) {142 auto SymName = Sym.getName();143 if (!SymName) {144 ES.reportError(SymName.takeError());145 R->failMaterialization();146 return;147 }148 149 // Already included in responsibility set, skip it150 SymbolStringPtr SymbolName = ES.intern(*SymName);151 if (R->getSymbols().count(SymbolName))152 continue;153 154 auto SymFlags = JITSymbolFlags::fromObjectSymbol(Sym);155 if (!SymFlags) {156 ES.reportError(SymFlags.takeError());157 R->failMaterialization();158 return;159 }160 161 ExtraSymbolsToClaim[SymbolName] = *SymFlags;162 continue;163 }164 165 // Don't include symbols that aren't global.166 if (!(*SymFlagsOrErr & object::BasicSymbolRef::SF_Global)) {167 if (auto SymName = Sym.getName())168 InternalSymbols->insert(*SymName);169 else {170 ES.reportError(SymName.takeError());171 R->failMaterialization();172 return;173 }174 }175 }176 177 if (!ExtraSymbolsToClaim.empty()) {178 if (auto Err = R->defineMaterializing(ExtraSymbolsToClaim)) {179 ES.reportError(std::move(Err));180 R->failMaterialization();181 }182 }183 }184 185 auto MemMgr = GetMemoryManager(*O);186 auto &MemMgrRef = *MemMgr;187 188 // Switch to shared ownership of MR so that it can be captured by both189 // lambdas below.190 std::shared_ptr<MaterializationResponsibility> SharedR(std::move(R));191 auto Deps = std::make_unique<SymbolDependenceMap>();192 193 auto Resolver =194 std::make_unique<JITDylibSearchOrderResolver>(*SharedR, *Deps);195 auto *ResolverPtr = Resolver.get();196 197 jitLinkForORC(198 object::OwningBinary<object::ObjectFile>(std::move(*Obj), std::move(O)),199 MemMgrRef, *ResolverPtr, ProcessAllSections,200 [this, SharedR, &MemMgrRef, InternalSymbols](201 const object::ObjectFile &Obj,202 RuntimeDyld::LoadedObjectInfo &LoadedObjInfo,203 std::map<StringRef, JITEvaluatedSymbol> ResolvedSymbols) {204 return onObjLoad(*SharedR, Obj, MemMgrRef, LoadedObjInfo,205 ResolvedSymbols, *InternalSymbols);206 },207 [this, SharedR, MemMgr = std::move(MemMgr), Deps = std::move(Deps),208 Resolver = std::move(Resolver)](209 object::OwningBinary<object::ObjectFile> Obj,210 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,211 Error Err) mutable {212 onObjEmit(*SharedR, std::move(Obj), std::move(MemMgr),213 std::move(LoadedObjInfo), std::move(Deps), std::move(Err));214 });215}216 217void RTDyldObjectLinkingLayer::registerJITEventListener(JITEventListener &L) {218 std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);219 assert(!llvm::is_contained(EventListeners, &L) &&220 "Listener has already been registered");221 EventListeners.push_back(&L);222}223 224void RTDyldObjectLinkingLayer::unregisterJITEventListener(JITEventListener &L) {225 std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);226 auto I = llvm::find(EventListeners, &L);227 assert(I != EventListeners.end() && "Listener not registered");228 EventListeners.erase(I);229}230 231Error RTDyldObjectLinkingLayer::onObjLoad(232 MaterializationResponsibility &R, const object::ObjectFile &Obj,233 RuntimeDyld::MemoryManager &MemMgr,234 RuntimeDyld::LoadedObjectInfo &LoadedObjInfo,235 std::map<StringRef, JITEvaluatedSymbol> Resolved,236 std::set<StringRef> &InternalSymbols) {237 SymbolFlagsMap ExtraSymbolsToClaim;238 SymbolMap Symbols;239 240 // Hack to support COFF constant pool comdats introduced during compilation:241 // (See http://llvm.org/PR40074)242 if (auto *COFFObj = dyn_cast<object::COFFObjectFile>(&Obj)) {243 auto &ES = getExecutionSession();244 245 // For all resolved symbols that are not already in the responsibility set:246 // check whether the symbol is in a comdat section and if so mark it as247 // weak.248 for (auto &Sym : COFFObj->symbols()) {249 // getFlags() on COFF symbols can't fail.250 uint32_t SymFlags = cantFail(Sym.getFlags());251 if (SymFlags & object::BasicSymbolRef::SF_Undefined)252 continue;253 auto Name = Sym.getName();254 if (!Name)255 return Name.takeError();256 auto I = Resolved.find(*Name);257 258 // Skip unresolved symbols, internal symbols, and symbols that are259 // already in the responsibility set.260 if (I == Resolved.end() || InternalSymbols.count(*Name) ||261 R.getSymbols().count(ES.intern(*Name)))262 continue;263 auto Sec = Sym.getSection();264 if (!Sec)265 return Sec.takeError();266 if (*Sec == COFFObj->section_end())267 continue;268 auto &COFFSec = *COFFObj->getCOFFSection(**Sec);269 if (COFFSec.Characteristics & COFF::IMAGE_SCN_LNK_COMDAT)270 I->second.setFlags(I->second.getFlags() | JITSymbolFlags::Weak);271 }272 273 // Handle any aliases.274 for (auto &Sym : COFFObj->symbols()) {275 uint32_t SymFlags = cantFail(Sym.getFlags());276 if (SymFlags & object::BasicSymbolRef::SF_Undefined)277 continue;278 auto Name = Sym.getName();279 if (!Name)280 return Name.takeError();281 auto I = Resolved.find(*Name);282 283 // Skip already-resolved symbols, and symbols that we're not responsible284 // for.285 if (I != Resolved.end() || !R.getSymbols().count(ES.intern(*Name)))286 continue;287 288 // Skip anything other than weak externals.289 auto COFFSym = COFFObj->getCOFFSymbol(Sym);290 if (!COFFSym.isWeakExternal())291 continue;292 auto *WeakExternal = COFFSym.getAux<object::coff_aux_weak_external>();293 if (WeakExternal->Characteristics != COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS)294 continue;295 296 // We found an alias. Reuse the resolution of the alias target for the297 // alias itself.298 Expected<object::COFFSymbolRef> TargetSymbol =299 COFFObj->getSymbol(WeakExternal->TagIndex);300 if (!TargetSymbol)301 return TargetSymbol.takeError();302 Expected<StringRef> TargetName = COFFObj->getSymbolName(*TargetSymbol);303 if (!TargetName)304 return TargetName.takeError();305 auto J = Resolved.find(*TargetName);306 if (J == Resolved.end())307 return make_error<StringError>("Could alias target " + *TargetName +308 " not resolved",309 inconvertibleErrorCode());310 Resolved[*Name] = J->second;311 }312 }313 314 for (auto &KV : Resolved) {315 // Scan the symbols and add them to the Symbols map for resolution.316 317 // We never claim internal symbols.318 if (InternalSymbols.count(KV.first))319 continue;320 321 auto InternedName = getExecutionSession().intern(KV.first);322 auto Flags = KV.second.getFlags();323 auto I = R.getSymbols().find(InternedName);324 if (I != R.getSymbols().end()) {325 // Override object flags and claim responsibility for symbols if326 // requested.327 if (OverrideObjectFlags)328 Flags = I->second;329 else {330 // RuntimeDyld/MCJIT's weak tracking isn't compatible with ORC's. Even331 // if we're not overriding flags in general we should set the weak flag332 // according to the MaterializationResponsibility object symbol table.333 if (I->second.isWeak())334 Flags |= JITSymbolFlags::Weak;335 }336 } else if (AutoClaimObjectSymbols)337 ExtraSymbolsToClaim[InternedName] = Flags;338 339 Symbols[InternedName] = {ExecutorAddr(KV.second.getAddress()), Flags};340 }341 342 if (!ExtraSymbolsToClaim.empty()) {343 if (auto Err = R.defineMaterializing(ExtraSymbolsToClaim))344 return Err;345 346 // If we claimed responsibility for any weak symbols but were rejected then347 // we need to remove them from the resolved set.348 for (auto &KV : ExtraSymbolsToClaim)349 if (KV.second.isWeak() && !R.getSymbols().count(KV.first))350 Symbols.erase(KV.first);351 }352 353 if (auto Err = R.notifyResolved(Symbols)) {354 R.failMaterialization();355 return Err;356 }357 358 if (NotifyLoaded)359 NotifyLoaded(R, Obj, LoadedObjInfo);360 361 return Error::success();362}363 364void RTDyldObjectLinkingLayer::onObjEmit(365 MaterializationResponsibility &R,366 object::OwningBinary<object::ObjectFile> O,367 std::unique_ptr<RuntimeDyld::MemoryManager> MemMgr,368 std::unique_ptr<RuntimeDyld::LoadedObjectInfo> LoadedObjInfo,369 std::unique_ptr<SymbolDependenceMap> Deps, Error Err) {370 if (Err) {371 getExecutionSession().reportError(std::move(Err));372 R.failMaterialization();373 return;374 }375 376 SymbolDependenceGroup SDG;377 for (auto &[Sym, Flags] : R.getSymbols())378 SDG.Symbols.insert(Sym);379 SDG.Dependencies = std::move(*Deps);380 381 if (auto Err = R.notifyEmitted(SDG)) {382 getExecutionSession().reportError(std::move(Err));383 R.failMaterialization();384 return;385 }386 387 std::unique_ptr<object::ObjectFile> Obj;388 std::unique_ptr<MemoryBuffer> ObjBuffer;389 std::tie(Obj, ObjBuffer) = O.takeBinary();390 391 // Run EventListener notifyLoaded callbacks.392 {393 std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);394 for (auto *L : EventListeners)395 L->notifyObjectLoaded(pointerToJITTargetAddress(MemMgr.get()), *Obj,396 *LoadedObjInfo);397 }398 399 if (NotifyEmitted)400 NotifyEmitted(R, std::move(ObjBuffer));401 402 if (auto Err = R.withResourceKeyDo(403 [&](ResourceKey K) { MemMgrs[K].push_back(std::move(MemMgr)); })) {404 getExecutionSession().reportError(std::move(Err));405 R.failMaterialization();406 }407}408 409Error RTDyldObjectLinkingLayer::handleRemoveResources(JITDylib &JD,410 ResourceKey K) {411 412 std::vector<MemoryManagerUP> MemMgrsToRemove;413 414 getExecutionSession().runSessionLocked([&] {415 auto I = MemMgrs.find(K);416 if (I != MemMgrs.end()) {417 std::swap(MemMgrsToRemove, I->second);418 MemMgrs.erase(I);419 }420 });421 422 {423 std::lock_guard<std::mutex> Lock(RTDyldLayerMutex);424 for (auto &MemMgr : MemMgrsToRemove) {425 for (auto *L : EventListeners)426 L->notifyFreeingObject(pointerToJITTargetAddress(MemMgr.get()));427 MemMgr->deregisterEHFrames();428 }429 }430 431 return Error::success();432}433 434void RTDyldObjectLinkingLayer::handleTransferResources(JITDylib &JD,435 ResourceKey DstKey,436 ResourceKey SrcKey) {437 if (MemMgrs.contains(SrcKey)) {438 // DstKey may not be in the DenseMap yet, so the following line may resize439 // the container and invalidate iterators and value references.440 auto &DstMemMgrs = MemMgrs[DstKey];441 auto &SrcMemMgrs = MemMgrs[SrcKey];442 DstMemMgrs.reserve(DstMemMgrs.size() + SrcMemMgrs.size());443 for (auto &MemMgr : SrcMemMgrs)444 DstMemMgrs.push_back(std::move(MemMgr));445 446 MemMgrs.erase(SrcKey);447 }448}449 450} // End namespace orc.451} // End namespace llvm.452