xref: /freebsd/contrib/llvm-project/llvm/lib/ExecutionEngine/JITLink/PerGraphGOTAndPLTStubsBuilder.h (revision 04eeddc0aa8e0a417a16eaf9d7d095207f4a8623)
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