1f2d18a4dSLang Hames //===----- JITLinkReentryTrampolines.cpp -- JITLink-based trampoline- -----===// 2f2d18a4dSLang Hames // 3f2d18a4dSLang Hames // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4f2d18a4dSLang Hames // See https://llvm.org/LICENSE.txt for license information. 5f2d18a4dSLang Hames // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6f2d18a4dSLang Hames // 7f2d18a4dSLang Hames //===----------------------------------------------------------------------===// 8f2d18a4dSLang Hames 9f2d18a4dSLang Hames #include "llvm/ExecutionEngine/Orc/JITLinkReentryTrampolines.h" 10f2d18a4dSLang Hames 11f2d18a4dSLang Hames #include "llvm/ExecutionEngine/JITLink/aarch64.h" 128daf4f16SLang Hames #include "llvm/ExecutionEngine/JITLink/x86_64.h" 13f2d18a4dSLang Hames #include "llvm/ExecutionEngine/Orc/ObjectLinkingLayer.h" 14f2d18a4dSLang Hames 15f2d18a4dSLang Hames #include <memory> 16f2d18a4dSLang Hames 17f2d18a4dSLang Hames #define DEBUG_TYPE "orc" 18f2d18a4dSLang Hames 19f2d18a4dSLang Hames using namespace llvm; 20f2d18a4dSLang Hames using namespace llvm::jitlink; 21f2d18a4dSLang Hames 22f2d18a4dSLang Hames namespace { 23f2d18a4dSLang Hames constexpr StringRef ReentryFnName = "__orc_rt_reenter"; 24f2d18a4dSLang Hames constexpr StringRef ReentrySectionName = "__orc_stubs"; 25f2d18a4dSLang Hames } // namespace 26f2d18a4dSLang Hames 27f2d18a4dSLang Hames namespace llvm::orc { 28f2d18a4dSLang Hames 29f2d18a4dSLang Hames class JITLinkReentryTrampolines::TrampolineAddrScraperPlugin 30f2d18a4dSLang Hames : public ObjectLinkingLayer::Plugin { 31f2d18a4dSLang Hames public: 32f2d18a4dSLang Hames void modifyPassConfig(MaterializationResponsibility &MR, 33f2d18a4dSLang Hames jitlink::LinkGraph &G, 34f2d18a4dSLang Hames jitlink::PassConfiguration &Config) override { 35f2d18a4dSLang Hames Config.PreFixupPasses.push_back( 36f2d18a4dSLang Hames [this](LinkGraph &G) { return recordTrampolineAddrs(G); }); 37f2d18a4dSLang Hames } 38f2d18a4dSLang Hames 39f2d18a4dSLang Hames Error notifyFailed(MaterializationResponsibility &MR) override { 40f2d18a4dSLang Hames return Error::success(); 41f2d18a4dSLang Hames } 42f2d18a4dSLang Hames 43f2d18a4dSLang Hames Error notifyRemovingResources(JITDylib &JD, ResourceKey K) override { 44f2d18a4dSLang Hames return Error::success(); 45f2d18a4dSLang Hames } 46f2d18a4dSLang Hames 47f2d18a4dSLang Hames void notifyTransferringResources(JITDylib &JD, ResourceKey DstKey, 48f2d18a4dSLang Hames ResourceKey SrcKey) override {} 49f2d18a4dSLang Hames 50f2d18a4dSLang Hames void registerGraph(LinkGraph &G, 51f2d18a4dSLang Hames std::shared_ptr<std::vector<ExecutorSymbolDef>> Addrs) { 52f2d18a4dSLang Hames std::lock_guard<std::mutex> Lock(M); 53f2d18a4dSLang Hames assert(!PendingAddrs.count(&G) && "Duplicate registration"); 54f2d18a4dSLang Hames PendingAddrs[&G] = std::move(Addrs); 55f2d18a4dSLang Hames } 56f2d18a4dSLang Hames 57f2d18a4dSLang Hames Error recordTrampolineAddrs(LinkGraph &G) { 58f2d18a4dSLang Hames std::shared_ptr<std::vector<ExecutorSymbolDef>> Addrs; 59f2d18a4dSLang Hames { 60f2d18a4dSLang Hames std::lock_guard<std::mutex> Lock(M); 61f2d18a4dSLang Hames auto I = PendingAddrs.find(&G); 62f2d18a4dSLang Hames if (I == PendingAddrs.end()) 63f2d18a4dSLang Hames return Error::success(); 64f2d18a4dSLang Hames Addrs = std::move(I->second); 65f2d18a4dSLang Hames PendingAddrs.erase(I); 66f2d18a4dSLang Hames } 67f2d18a4dSLang Hames 68f2d18a4dSLang Hames auto *Sec = G.findSectionByName(ReentrySectionName); 69f2d18a4dSLang Hames assert(Sec && "Reentry graph missing reentry section"); 70f2d18a4dSLang Hames assert(!Sec->empty() && "Reentry graph is empty"); 71f2d18a4dSLang Hames 72f2d18a4dSLang Hames for (auto *Sym : Sec->symbols()) 73f2d18a4dSLang Hames if (!Sym->hasName()) 74f2d18a4dSLang Hames Addrs->push_back({Sym->getAddress(), JITSymbolFlags()}); 75f2d18a4dSLang Hames 76f2d18a4dSLang Hames return Error::success(); 77f2d18a4dSLang Hames } 78f2d18a4dSLang Hames 79f2d18a4dSLang Hames private: 80f2d18a4dSLang Hames std::mutex M; 81f2d18a4dSLang Hames DenseMap<LinkGraph *, std::shared_ptr<std::vector<ExecutorSymbolDef>>> 82f2d18a4dSLang Hames PendingAddrs; 83f2d18a4dSLang Hames }; 84f2d18a4dSLang Hames 85f2d18a4dSLang Hames Expected<std::unique_ptr<JITLinkReentryTrampolines>> 86f2d18a4dSLang Hames JITLinkReentryTrampolines::Create(ObjectLinkingLayer &ObjLinkingLayer) { 87f2d18a4dSLang Hames 88f2d18a4dSLang Hames EmitTrampolineFn EmitTrampoline; 89f2d18a4dSLang Hames 9081c680a8SLang Hames const auto &TT = ObjLinkingLayer.getExecutionSession().getTargetTriple(); 9181c680a8SLang Hames switch (TT.getArch()) { 92f2d18a4dSLang Hames case Triple::aarch64: 93f2d18a4dSLang Hames EmitTrampoline = aarch64::createAnonymousReentryTrampoline; 94f2d18a4dSLang Hames break; 958daf4f16SLang Hames case Triple::x86_64: 968daf4f16SLang Hames EmitTrampoline = x86_64::createAnonymousReentryTrampoline; 978daf4f16SLang Hames break; 98f2d18a4dSLang Hames default: 9981c680a8SLang Hames return make_error<StringError>("JITLinkReentryTrampolines: architecture " + 10081c680a8SLang Hames TT.getArchName() + " not supported", 101f2d18a4dSLang Hames inconvertibleErrorCode()); 102f2d18a4dSLang Hames } 103f2d18a4dSLang Hames 104f2d18a4dSLang Hames return std::make_unique<JITLinkReentryTrampolines>(ObjLinkingLayer, 105f2d18a4dSLang Hames std::move(EmitTrampoline)); 106f2d18a4dSLang Hames } 107f2d18a4dSLang Hames 108f2d18a4dSLang Hames JITLinkReentryTrampolines::JITLinkReentryTrampolines( 109f2d18a4dSLang Hames ObjectLinkingLayer &ObjLinkingLayer, EmitTrampolineFn EmitTrampoline) 110f2d18a4dSLang Hames : ObjLinkingLayer(ObjLinkingLayer), 111f2d18a4dSLang Hames EmitTrampoline(std::move(EmitTrampoline)) { 112f2d18a4dSLang Hames auto TAS = std::make_shared<TrampolineAddrScraperPlugin>(); 113f2d18a4dSLang Hames TrampolineAddrScraper = TAS.get(); 114f2d18a4dSLang Hames ObjLinkingLayer.addPlugin(std::move(TAS)); 115f2d18a4dSLang Hames } 116f2d18a4dSLang Hames 117f2d18a4dSLang Hames void JITLinkReentryTrampolines::emit(ResourceTrackerSP RT, 118f2d18a4dSLang Hames size_t NumTrampolines, 119f2d18a4dSLang Hames OnTrampolinesReadyFn OnTrampolinesReady) { 120f2d18a4dSLang Hames 121f2d18a4dSLang Hames if (NumTrampolines == 0) 122f2d18a4dSLang Hames return OnTrampolinesReady(std::vector<ExecutorSymbolDef>()); 123f2d18a4dSLang Hames 124f2d18a4dSLang Hames JITDylibSP JD(&RT->getJITDylib()); 125f2d18a4dSLang Hames auto &ES = ObjLinkingLayer.getExecutionSession(); 126f2d18a4dSLang Hames 127f2d18a4dSLang Hames auto ReentryGraphSym = 128f2d18a4dSLang Hames ES.intern(("__orc_reentry_graph_#" + Twine(++ReentryGraphIdx)).str()); 129f2d18a4dSLang Hames 130f2d18a4dSLang Hames auto G = std::make_unique<jitlink::LinkGraph>( 131*4eaff6c5SLang Hames (*ReentryGraphSym).str(), ES.getSymbolStringPool(), ES.getTargetTriple(), 132*4eaff6c5SLang Hames SubtargetFeatures(), jitlink::getGenericEdgeKindName); 133f2d18a4dSLang Hames 134f2d18a4dSLang Hames auto &ReentryFnSym = G->addExternalSymbol(ReentryFnName, 0, false); 135f2d18a4dSLang Hames 136f2d18a4dSLang Hames auto &ReentrySection = 137f2d18a4dSLang Hames G->createSection(ReentrySectionName, MemProt::Exec | MemProt::Read); 138f2d18a4dSLang Hames 139f2d18a4dSLang Hames for (size_t I = 0; I != NumTrampolines; ++I) 140f2d18a4dSLang Hames EmitTrampoline(*G, ReentrySection, ReentryFnSym).setLive(true); 141f2d18a4dSLang Hames 142f2d18a4dSLang Hames auto &FirstBlock = **ReentrySection.blocks().begin(); 143f2d18a4dSLang Hames G->addDefinedSymbol(FirstBlock, 0, *ReentryGraphSym, FirstBlock.getSize(), 144f2d18a4dSLang Hames Linkage::Strong, Scope::SideEffectsOnly, true, true); 145f2d18a4dSLang Hames 146f2d18a4dSLang Hames auto TrampolineAddrs = std::make_shared<std::vector<ExecutorSymbolDef>>(); 147f2d18a4dSLang Hames TrampolineAddrScraper->registerGraph(*G, TrampolineAddrs); 148f2d18a4dSLang Hames 149f2d18a4dSLang Hames // Add Graph via object linking layer. 150f2d18a4dSLang Hames if (auto Err = ObjLinkingLayer.add(std::move(RT), std::move(G))) 151f2d18a4dSLang Hames return OnTrampolinesReady(std::move(Err)); 152f2d18a4dSLang Hames 153f2d18a4dSLang Hames // Trigger graph emission. 154f2d18a4dSLang Hames ES.lookup( 155f2d18a4dSLang Hames LookupKind::Static, {{JD.get(), JITDylibLookupFlags::MatchAllSymbols}}, 156f2d18a4dSLang Hames SymbolLookupSet(ReentryGraphSym, 157f2d18a4dSLang Hames SymbolLookupFlags::WeaklyReferencedSymbol), 158f2d18a4dSLang Hames SymbolState::Ready, 159f2d18a4dSLang Hames [OnTrampolinesReady = std::move(OnTrampolinesReady), 160f2d18a4dSLang Hames TrampolineAddrs = 161f2d18a4dSLang Hames std::move(TrampolineAddrs)](Expected<SymbolMap> Result) mutable { 162f2d18a4dSLang Hames if (Result) 163f2d18a4dSLang Hames OnTrampolinesReady(std::move(*TrampolineAddrs)); 164f2d18a4dSLang Hames else 165f2d18a4dSLang Hames OnTrampolinesReady(Result.takeError()); 166f2d18a4dSLang Hames }, 167f2d18a4dSLang Hames NoDependenciesToRegister); 168f2d18a4dSLang Hames } 169f2d18a4dSLang Hames 170f2d18a4dSLang Hames Expected<std::unique_ptr<LazyReexportsManager>> 171f2d18a4dSLang Hames createJITLinkLazyReexportsManager(ObjectLinkingLayer &ObjLinkingLayer, 172f2d18a4dSLang Hames RedirectableSymbolManager &RSMgr, 1732d10b7b7SLang Hames JITDylib &PlatformJD, 1742d10b7b7SLang Hames LazyReexportsManager::Listener *L) { 175f2d18a4dSLang Hames auto JLT = JITLinkReentryTrampolines::Create(ObjLinkingLayer); 176f2d18a4dSLang Hames if (!JLT) 177f2d18a4dSLang Hames return JLT.takeError(); 178f2d18a4dSLang Hames 179f2d18a4dSLang Hames return LazyReexportsManager::Create( 180f2d18a4dSLang Hames [JLT = std::move(*JLT)](ResourceTrackerSP RT, size_t NumTrampolines, 181f2d18a4dSLang Hames LazyReexportsManager::OnTrampolinesReadyFn 182f2d18a4dSLang Hames OnTrampolinesReady) mutable { 183f2d18a4dSLang Hames JLT->emit(std::move(RT), NumTrampolines, std::move(OnTrampolinesReady)); 184f2d18a4dSLang Hames }, 1852d10b7b7SLang Hames RSMgr, PlatformJD, L); 186f2d18a4dSLang Hames } 187f2d18a4dSLang Hames 188f2d18a4dSLang Hames } // namespace llvm::orc 189