1fe6060f1SDimitry Andric //===--------------- PerGraphGOTAndPLTStubBuilder.h -------------*- C++ -*-===// 2fe6060f1SDimitry Andric // 3fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6fe6060f1SDimitry Andric // 7fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 8fe6060f1SDimitry Andric // 9fe6060f1SDimitry Andric // Construct GOT and PLT entries for each graph. 10fe6060f1SDimitry Andric // 11fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 12fe6060f1SDimitry Andric 13fe6060f1SDimitry Andric #ifndef LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H 14fe6060f1SDimitry Andric #define LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H 15fe6060f1SDimitry Andric 16fe6060f1SDimitry Andric #include "llvm/ExecutionEngine/JITLink/JITLink.h" 17fe6060f1SDimitry Andric #include "llvm/Support/Debug.h" 18fe6060f1SDimitry Andric 19fe6060f1SDimitry Andric #define DEBUG_TYPE "jitlink" 20fe6060f1SDimitry Andric 21fe6060f1SDimitry Andric namespace llvm { 22fe6060f1SDimitry Andric namespace jitlink { 23fe6060f1SDimitry Andric 24fe6060f1SDimitry Andric /// Per-object GOT and PLT Stub builder. 25fe6060f1SDimitry Andric /// 26fe6060f1SDimitry Andric /// Constructs GOT entries and PLT stubs in every graph for referenced symbols. 27fe6060f1SDimitry Andric /// Building these blocks in every graph is likely to lead to duplicate entries 28fe6060f1SDimitry Andric /// in the JITLinkDylib, but allows graphs to be trivially removed independently 29fe6060f1SDimitry Andric /// without affecting other graphs (since those other graphs will have their own 30fe6060f1SDimitry Andric /// copies of any required entries). 31fe6060f1SDimitry Andric template <typename BuilderImplT> 32fe6060f1SDimitry Andric class PerGraphGOTAndPLTStubsBuilder { 33fe6060f1SDimitry Andric public: PerGraphGOTAndPLTStubsBuilder(LinkGraph & G)34fe6060f1SDimitry Andric PerGraphGOTAndPLTStubsBuilder(LinkGraph &G) : G(G) {} 35fe6060f1SDimitry Andric asPass(LinkGraph & G)36fe6060f1SDimitry Andric static Error asPass(LinkGraph &G) { return BuilderImplT(G).run(); } 37fe6060f1SDimitry Andric run()38fe6060f1SDimitry Andric Error run() { 39fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Running Per-Graph GOT and Stubs builder:\n"); 40fe6060f1SDimitry Andric 41fe6060f1SDimitry Andric // We're going to be adding new blocks, but we don't want to iterate over 42fe6060f1SDimitry Andric // the new ones, so build a worklist. 43fe6060f1SDimitry Andric std::vector<Block *> Worklist(G.blocks().begin(), G.blocks().end()); 44fe6060f1SDimitry Andric 45fe6060f1SDimitry Andric for (auto *B : Worklist) 46fe6060f1SDimitry Andric for (auto &E : B->edges()) { 47fe6060f1SDimitry Andric if (impl().isGOTEdgeToFix(E)) { 48fe6060f1SDimitry Andric LLVM_DEBUG({ 49fe6060f1SDimitry Andric dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) 50*04eeddc0SDimitry Andric << " edge at " << B->getFixupAddress(E) << " (" 51*04eeddc0SDimitry Andric << B->getAddress() << " + " 52fe6060f1SDimitry Andric << formatv("{0:x}", E.getOffset()) << ")\n"; 53fe6060f1SDimitry Andric }); 54fe6060f1SDimitry Andric impl().fixGOTEdge(E, getGOTEntry(E.getTarget())); 55fe6060f1SDimitry Andric } else if (impl().isExternalBranchEdge(E)) { 56fe6060f1SDimitry Andric LLVM_DEBUG({ 57fe6060f1SDimitry Andric dbgs() << " Fixing " << G.getEdgeKindName(E.getKind()) 58*04eeddc0SDimitry Andric << " edge at " << B->getFixupAddress(E) << " (" 59*04eeddc0SDimitry Andric << B->getAddress() << " + " 60fe6060f1SDimitry Andric << formatv("{0:x}", E.getOffset()) << ")\n"; 61fe6060f1SDimitry Andric }); 62fe6060f1SDimitry Andric impl().fixPLTEdge(E, getPLTStub(E.getTarget())); 63fe6060f1SDimitry Andric } 64fe6060f1SDimitry Andric } 65fe6060f1SDimitry Andric 66fe6060f1SDimitry Andric return Error::success(); 67fe6060f1SDimitry Andric } 68fe6060f1SDimitry Andric 69fe6060f1SDimitry Andric protected: getGOTEntry(Symbol & Target)70fe6060f1SDimitry Andric Symbol &getGOTEntry(Symbol &Target) { 71fe6060f1SDimitry Andric assert(Target.hasName() && "GOT edge cannot point to anonymous target"); 72fe6060f1SDimitry Andric 73fe6060f1SDimitry Andric auto GOTEntryI = GOTEntries.find(Target.getName()); 74fe6060f1SDimitry Andric 75fe6060f1SDimitry Andric // Build the entry if it doesn't exist. 76fe6060f1SDimitry Andric if (GOTEntryI == GOTEntries.end()) { 77fe6060f1SDimitry Andric auto &GOTEntry = impl().createGOTEntry(Target); 78fe6060f1SDimitry Andric LLVM_DEBUG({ 79fe6060f1SDimitry Andric dbgs() << " Created GOT entry for " << Target.getName() << ": " 80fe6060f1SDimitry Andric << GOTEntry << "\n"; 81fe6060f1SDimitry Andric }); 82fe6060f1SDimitry Andric GOTEntryI = 83fe6060f1SDimitry Andric GOTEntries.insert(std::make_pair(Target.getName(), &GOTEntry)).first; 84fe6060f1SDimitry Andric } 85fe6060f1SDimitry Andric 86fe6060f1SDimitry Andric assert(GOTEntryI != GOTEntries.end() && "Could not get GOT entry symbol"); 87fe6060f1SDimitry Andric LLVM_DEBUG( 88fe6060f1SDimitry Andric { dbgs() << " Using GOT entry " << *GOTEntryI->second << "\n"; }); 89fe6060f1SDimitry Andric return *GOTEntryI->second; 90fe6060f1SDimitry Andric } 91fe6060f1SDimitry Andric getPLTStub(Symbol & Target)92fe6060f1SDimitry Andric Symbol &getPLTStub(Symbol &Target) { 93fe6060f1SDimitry Andric assert(Target.hasName() && 94fe6060f1SDimitry Andric "External branch edge can not point to an anonymous target"); 95fe6060f1SDimitry Andric auto StubI = PLTStubs.find(Target.getName()); 96fe6060f1SDimitry Andric 97fe6060f1SDimitry Andric if (StubI == PLTStubs.end()) { 98fe6060f1SDimitry Andric auto &StubSymbol = impl().createPLTStub(Target); 99fe6060f1SDimitry Andric LLVM_DEBUG({ 100fe6060f1SDimitry Andric dbgs() << " Created PLT stub for " << Target.getName() << ": " 101fe6060f1SDimitry Andric << StubSymbol << "\n"; 102fe6060f1SDimitry Andric }); 103fe6060f1SDimitry Andric StubI = 104fe6060f1SDimitry Andric PLTStubs.insert(std::make_pair(Target.getName(), &StubSymbol)).first; 105fe6060f1SDimitry Andric } 106fe6060f1SDimitry Andric 107fe6060f1SDimitry Andric assert(StubI != PLTStubs.end() && "Count not get stub symbol"); 108fe6060f1SDimitry Andric LLVM_DEBUG({ dbgs() << " Using PLT stub " << *StubI->second << "\n"; }); 109fe6060f1SDimitry Andric return *StubI->second; 110fe6060f1SDimitry Andric } 111fe6060f1SDimitry Andric 112fe6060f1SDimitry Andric LinkGraph &G; 113fe6060f1SDimitry Andric 114fe6060f1SDimitry Andric private: impl()115fe6060f1SDimitry Andric BuilderImplT &impl() { return static_cast<BuilderImplT &>(*this); } 116fe6060f1SDimitry Andric 117fe6060f1SDimitry Andric DenseMap<StringRef, Symbol *> GOTEntries; 118fe6060f1SDimitry Andric DenseMap<StringRef, Symbol *> PLTStubs; 119fe6060f1SDimitry Andric }; 120fe6060f1SDimitry Andric 121fe6060f1SDimitry Andric } // end namespace jitlink 122fe6060f1SDimitry Andric } // end namespace llvm 123fe6060f1SDimitry Andric 124fe6060f1SDimitry Andric #undef DEBUG_TYPE 125fe6060f1SDimitry Andric 126fe6060f1SDimitry Andric #endif // LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H 127