| //===--------------- PerGraphGOTAndPLTStubBuilder.h -------------*- 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 |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // Construct GOT and PLT entries for each graph. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H |
| #define LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H |
| |
| #include "llvm/ExecutionEngine/JITLink/JITLink.h" |
| #include "llvm/Support/Debug.h" |
| |
| #define DEBUG_TYPE "jitlink" |
| |
| namespace llvm { |
| namespace jitlink { |
| |
| /// Per-object GOT and PLT Stub builder. |
| /// |
| /// Constructs GOT entries and PLT stubs in every graph for referenced symbols. |
| /// Building these blocks in every graph is likely to lead to duplicate entries |
| /// in the JITLinkDylib, but allows graphs to be trivially removed independently |
| /// without affecting other graphs (since those other graphs will have their own |
| /// copies of any required entries). |
| template <typename BuilderImplT> |
| class PerGraphGOTAndPLTStubsBuilder { |
| public: |
| PerGraphGOTAndPLTStubsBuilder(LinkGraph &G) : G(G) {} |
| |
| static Error asPass(LinkGraph &G) { return BuilderImplT(G).run(); } |
| |
| Error run() { |
| LLVM_DEBUG(dbgs() << "Running Per-Graph GOT and Stubs builder:\n"); |
| |
| // We're going to be adding new blocks, but we don't want to iterate over |
| // the new ones, so build a worklist. |
| std::vector<Block *> Worklist(G.blocks().begin(), G.blocks().end()); |
| |
| for (auto *B : Worklist) |
| for (auto &E : B->edges()) { |
| if (impl().isGOTEdgeToFix(E)) { |
| LLVM_DEBUG({ |
| dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) |
| << " edge at " << B->getFixupAddress(E) << " (" |
| << B->getAddress() << " + " |
| << formatv("{0:x}", E.getOffset()) << ")\n"; |
| }); |
| impl().fixGOTEdge(E, getGOTEntry(E.getTarget())); |
| } else if (impl().isExternalBranchEdge(E)) { |
| LLVM_DEBUG({ |
| dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) |
| << " edge at " << B->getFixupAddress(E) << " (" |
| << B->getAddress() << " + " |
| << formatv("{0:x}", E.getOffset()) << ")\n"; |
| }); |
| impl().fixPLTEdge(E, getPLTStub(E.getTarget())); |
| } |
| } |
| |
| return Error::success(); |
| } |
| |
| protected: |
| Symbol &getGOTEntry(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 &getPLTStub(Symbol &Target) { |
| assert(Target.hasName() && |
| "External branch edge can not point to an anonymous target"); |
| auto StubI = PLTStubs.find(Target.getName()); |
| |
| if (StubI == PLTStubs.end()) { |
| auto &StubSymbol = impl().createPLTStub(Target); |
| LLVM_DEBUG({ |
| dbgs() << " Created PLT stub for " << Target.getName() << ": " |
| << StubSymbol << "\n"; |
| }); |
| StubI = |
| PLTStubs.insert(std::make_pair(Target.getName(), &StubSymbol)).first; |
| } |
| |
| assert(StubI != PLTStubs.end() && "Count not get stub symbol"); |
| LLVM_DEBUG({ dbgs() << " Using PLT stub " << *StubI->second << "\n"; }); |
| return *StubI->second; |
| } |
| |
| LinkGraph &G; |
| |
| private: |
| BuilderImplT &impl() { return static_cast<BuilderImplT &>(*this); } |
| |
| DenseMap<StringRef, Symbol *> GOTEntries; |
| DenseMap<StringRef, Symbol *> PLTStubs; |
| }; |
| |
| } // end namespace jitlink |
| } // end namespace llvm |
| |
| #undef DEBUG_TYPE |
| |
| #endif // LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H |