//===----- JITLinkReentryTrampolines.cpp -- JITLink-based trampoline- -----===// // // 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/JITLinkReentryTrampolines.h" #include "llvm/ExecutionEngine/JITLink/aarch64.h" #include "llvm/ExecutionEngine/JITLink/x86_64.h" #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" #include #define DEBUG_TYPE "orc" using namespace llvm; using namespace llvm::jitlink; namespace { constexpr StringRef ReentryFnName = "__orc_rt_reenter"; constexpr StringRef ReentrySectionName = "__orc_stubs"; } // namespace namespace llvm::orc { class JITLinkReentryTrampolines::TrampolineAddrScraperPlugin : public ObjectLinkingLayer::Plugin { public: void modifyPassConfig(MaterializationResponsibility &MR, jitlink::LinkGraph &G, jitlink::PassConfiguration &Config) override { Config.PreFixupPasses.push_back( [this](LinkGraph &G) { return recordTrampolineAddrs(G); }); } Error notifyFailed(MaterializationResponsibility &MR) override { return Error::success(); } Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { return Error::success(); } void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, ResourceKey SrcKey) override {} void registerGraph(LinkGraph &G, std::shared_ptr> Addrs) { std::lock_guard Lock(M); assert(!PendingAddrs.count(&G) && "Duplicate registration"); PendingAddrs[&G] = std::move(Addrs); } Error recordTrampolineAddrs(LinkGraph &G) { std::shared_ptr> Addrs; { std::lock_guard Lock(M); auto I = PendingAddrs.find(&G); if (I == PendingAddrs.end()) return Error::success(); Addrs = std::move(I->second); PendingAddrs.erase(I); } auto *Sec = G.findSectionByName(ReentrySectionName); assert(Sec && "Reentry graph missing reentry section"); assert(!Sec->empty() && "Reentry graph is empty"); for (auto *Sym : Sec->symbols()) if (!Sym->hasName()) Addrs->push_back({Sym->getAddress(), JITSymbolFlags()}); return Error::success(); } private: std::mutex M; DenseMap>> PendingAddrs; }; Expected> JITLinkReentryTrampolines::Create(ObjectLinkingLayer &ObjLinkingLayer) { EmitTrampolineFn EmitTrampoline; const auto &TT = ObjLinkingLayer.getExecutionSession().getTargetTriple(); switch (TT.getArch()) { case Triple::aarch64: EmitTrampoline = aarch64::createAnonymousReentryTrampoline; break; case Triple::x86_64: EmitTrampoline = x86_64::createAnonymousReentryTrampoline; break; default: return make_error("JITLinkReentryTrampolines: architecture " + TT.getArchName() + " not supported", inconvertibleErrorCode()); } return std::make_unique(ObjLinkingLayer, std::move(EmitTrampoline)); } JITLinkReentryTrampolines::JITLinkReentryTrampolines( ObjectLinkingLayer &ObjLinkingLayer, EmitTrampolineFn EmitTrampoline) : ObjLinkingLayer(ObjLinkingLayer), EmitTrampoline(std::move(EmitTrampoline)) { auto TAS = std::make_shared(); TrampolineAddrScraper = TAS.get(); ObjLinkingLayer.addPlugin(std::move(TAS)); } void JITLinkReentryTrampolines::emit(ResourceTrackerSP RT, size_t NumTrampolines, OnTrampolinesReadyFn OnTrampolinesReady) { if (NumTrampolines == 0) return OnTrampolinesReady(std::vector()); JITDylibSP JD(&RT->getJITDylib()); auto &ES = ObjLinkingLayer.getExecutionSession(); auto ReentryGraphSym = ES.intern(("__orc_reentry_graph_#" + Twine(++ReentryGraphIdx)).str()); auto G = std::make_unique( (*ReentryGraphSym).str(), ES.getSymbolStringPool(), ES.getTargetTriple(), SubtargetFeatures(), jitlink::getGenericEdgeKindName); auto &ReentryFnSym = G->addExternalSymbol(ReentryFnName, 0, false); auto &ReentrySection = G->createSection(ReentrySectionName, MemProt::Exec | MemProt::Read); for (size_t I = 0; I != NumTrampolines; ++I) EmitTrampoline(*G, ReentrySection, ReentryFnSym).setLive(true); auto &FirstBlock = **ReentrySection.blocks().begin(); G->addDefinedSymbol(FirstBlock, 0, *ReentryGraphSym, FirstBlock.getSize(), Linkage::Strong, Scope::SideEffectsOnly, true, true); auto TrampolineAddrs = std::make_shared>(); TrampolineAddrScraper->registerGraph(*G, TrampolineAddrs); // Add Graph via object linking layer. if (auto Err = ObjLinkingLayer.add(std::move(RT), std::move(G))) return OnTrampolinesReady(std::move(Err)); // Trigger graph emission. ES.lookup( LookupKind::Static, {{JD.get(), JITDylibLookupFlags::MatchAllSymbols}}, SymbolLookupSet(ReentryGraphSym, SymbolLookupFlags::WeaklyReferencedSymbol), SymbolState::Ready, [OnTrampolinesReady = std::move(OnTrampolinesReady), TrampolineAddrs = std::move(TrampolineAddrs)](Expected Result) mutable { if (Result) OnTrampolinesReady(std::move(*TrampolineAddrs)); else OnTrampolinesReady(Result.takeError()); }, NoDependenciesToRegister); } Expected> createJITLinkLazyReexportsManager(ObjectLinkingLayer &ObjLinkingLayer, RedirectableSymbolManager &RSMgr, JITDylib &PlatformJD, LazyReexportsManager::Listener *L) { auto JLT = JITLinkReentryTrampolines::Create(ObjLinkingLayer); if (!JLT) return JLT.takeError(); return LazyReexportsManager::Create( [JLT = std::move(*JLT)](ResourceTrackerSP RT, size_t NumTrampolines, LazyReexportsManager::OnTrampolinesReadyFn OnTrampolinesReady) mutable { JLT->emit(std::move(RT), NumTrampolines, std::move(OnTrampolinesReady)); }, RSMgr, PlatformJD, L); } } // namespace llvm::orc