//===--- BasicGOTAndStubsBuilder.h - Generic GOT/Stub creation --*- C++ -*-===// // // 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 // //===----------------------------------------------------------------------===// // // A base for simple GOT and stub creation. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H #define LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H #include "llvm/ExecutionEngine/JITLink/JITLink.h" #define DEBUG_TYPE "jitlink" namespace llvm { namespace jitlink { template class BasicGOTAndStubsBuilder { public: BasicGOTAndStubsBuilder(LinkGraph &G) : G(G) {} void run() { // We're going to be adding new blocks, but we don't want to iterate over // the newly added ones, so just copy the existing blocks out. std::vector Blocks(G.blocks().begin(), G.blocks().end()); LLVM_DEBUG(dbgs() << "Creating GOT entries and stubs:\n"); for (auto *B : Blocks) for (auto &E : B->edges()) if (impl().isGOTEdge(E)) { LLVM_DEBUG({ dbgs() << " Updating GOT edge "; printEdge(dbgs(), *B, E, ""); dbgs() << "\n"; }); impl().fixGOTEdge(E, getGOTEntrySymbol(E.getTarget())); } else if (impl().isExternalBranchEdge(E)) { LLVM_DEBUG({ dbgs() << " Updating external branch edge "; printEdge(dbgs(), *B, E, ""); dbgs() << "\n"; }); impl().fixExternalBranchEdge(E, getStubSymbol(E.getTarget())); } } protected: Symbol &getGOTEntrySymbol(Symbol &Target) { assert(Target.hasName() && "GOT edge cannot point to anonymous target"); auto GOTEntryI = GOTEntries.find(Target.getName()); // Build the entry if it doesn't exist. if (GOTEntryI == GOTEntries.end()) { auto &GOTEntry = impl().createGOTEntry(Target); LLVM_DEBUG({ dbgs() << " Created GOT entry for " << Target.getName() << ": " << GOTEntry << "\n"; }); GOTEntryI = GOTEntries.insert(std::make_pair(Target.getName(), &GOTEntry)).first; } assert(GOTEntryI != GOTEntries.end() && "Could not get GOT entry symbol"); LLVM_DEBUG( { dbgs() << " Using GOT entry " << *GOTEntryI->second << "\n"; }); return *GOTEntryI->second; } Symbol &getStubSymbol(Symbol &Target) { assert(Target.hasName() && "External branch edge can not point to an anonymous target"); auto StubI = Stubs.find(Target.getName()); if (StubI == Stubs.end()) { auto &StubSymbol = impl().createStub(Target); LLVM_DEBUG({ dbgs() << " Created stub for " << Target.getName() << ": " << StubSymbol << "\n"; }); StubI = Stubs.insert(std::make_pair(Target.getName(), &StubSymbol)).first; } assert(StubI != Stubs.end() && "Count not get stub symbol"); LLVM_DEBUG({ dbgs() << " Using stub " << *StubI->second << "\n"; }); return *StubI->second; } LinkGraph &G; private: BuilderImpl &impl() { return static_cast(*this); } DenseMap GOTEntries; DenseMap Stubs; }; } // end namespace jitlink } // end namespace llvm #endif // LLVM_LIB_EXECUTIONENGINE_JITLINK_BASICGOTANDSTUBSBUILDER_H