1 //===--------------- PerGraphGOTAndPLTStubBuilder.h -------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 // Construct GOT and PLT entries for each graph.
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H
14 #define LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H
16 #include "llvm/ExecutionEngine/JITLink/JITLink.h"
17 #include "llvm/Support/Debug.h"
19 #define DEBUG_TYPE "jitlink"
24 /// Per-object GOT and PLT Stub builder.
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
{
34 PerGraphGOTAndPLTStubsBuilder(LinkGraph
&G
) : G(G
) {}
36 static Error
asPass(LinkGraph
&G
) { return BuilderImplT(G
).run(); }
39 LLVM_DEBUG(dbgs() << "Running Per-Graph GOT and Stubs builder:\n");
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());
45 for (auto *B
: Worklist
)
46 for (auto &E
: B
->edges()) {
47 if (impl().isGOTEdgeToFix(E
)) {
49 dbgs() << " Fixing " << G
.getEdgeKindName(E
.getKind())
50 << " edge at " << B
->getFixupAddress(E
) << " ("
51 << B
->getAddress() << " + "
52 << formatv("{0:x}", E
.getOffset()) << ")\n";
54 impl().fixGOTEdge(E
, getGOTEntry(E
.getTarget()));
55 } else if (impl().isExternalBranchEdge(E
)) {
57 dbgs() << " Fixing " << G
.getEdgeKindName(E
.getKind())
58 << " edge at " << B
->getFixupAddress(E
) << " ("
59 << B
->getAddress() << " + "
60 << formatv("{0:x}", E
.getOffset()) << ")\n";
62 impl().fixPLTEdge(E
, getPLTStub(E
.getTarget()));
66 return Error::success();
70 Symbol
&getGOTEntry(Symbol
&Target
) {
71 assert(Target
.hasName() && "GOT edge cannot point to anonymous target");
73 auto GOTEntryI
= GOTEntries
.find(Target
.getName());
75 // Build the entry if it doesn't exist.
76 if (GOTEntryI
== GOTEntries
.end()) {
77 auto &GOTEntry
= impl().createGOTEntry(Target
);
79 dbgs() << " Created GOT entry for " << Target
.getName() << ": "
83 GOTEntries
.insert(std::make_pair(Target
.getName(), &GOTEntry
)).first
;
86 assert(GOTEntryI
!= GOTEntries
.end() && "Could not get GOT entry symbol");
88 { dbgs() << " Using GOT entry " << *GOTEntryI
->second
<< "\n"; });
89 return *GOTEntryI
->second
;
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(Target
.getName());
97 if (StubI
== PLTStubs
.end()) {
98 auto &StubSymbol
= impl().createPLTStub(Target
);
100 dbgs() << " Created PLT stub for " << Target
.getName() << ": "
101 << StubSymbol
<< "\n";
104 PLTStubs
.insert(std::make_pair(Target
.getName(), &StubSymbol
)).first
;
107 assert(StubI
!= PLTStubs
.end() && "Count not get stub symbol");
108 LLVM_DEBUG({ dbgs() << " Using PLT stub " << *StubI
->second
<< "\n"; });
109 return *StubI
->second
;
115 BuilderImplT
&impl() { return static_cast<BuilderImplT
&>(*this); }
117 DenseMap
<StringRef
, Symbol
*> GOTEntries
;
118 DenseMap
<StringRef
, Symbol
*> PLTStubs
;
121 } // end namespace jitlink
122 } // end namespace llvm
126 #endif // LLVM_EXECUTIONENGINE_JITLINK_PERGRAPHGOTANDPLTSTUBSBUILDER_H