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