1//===- bolt/Rewrite/JITLinkLinker.cpp - BOLTLinker using JITLink ----------===//
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#include "bolt/Rewrite/JITLinkLinker.h"
10#include "bolt/Core/BinaryContext.h"
11#include "bolt/Core/BinaryData.h"
12#include "bolt/Core/BinarySection.h"
13#include "llvm/ExecutionEngine/JITLink/ELF_riscv.h"
14#include "llvm/ExecutionEngine/JITLink/JITLink.h"
15#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
16#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
17#include "llvm/Support/Debug.h"
18
19#define DEBUG_TYPE "bolt"
20
21namespace llvm {
22namespace bolt {
23
24namespace {
25
26bool hasSymbols(const jitlink::Block &B) {
27 return llvm::any_of(Range: B.getSection().symbols(),
28 P: [&B](const auto &S) { return &S->getBlock() == &B; });
29}
30
31/// Liveness in JITLink is based on symbols so sections that do not contain
32/// any symbols will always be pruned. This pass adds anonymous symbols to
33/// needed sections to prevent pruning.
34Error markSectionsLive(jitlink::LinkGraph &G) {
35 for (auto &Section : G.sections()) {
36 // We only need allocatable sections.
37 if (Section.getMemLifetime() == orc::MemLifetime::NoAlloc)
38 continue;
39
40 // Skip empty sections.
41 if (JITLinkLinker::sectionSize(Section) == 0)
42 continue;
43
44 for (auto *Block : Section.blocks()) {
45 // No need to add symbols if it already has some.
46 if (hasSymbols(B: *Block))
47 continue;
48
49 G.addAnonymousSymbol(Content&: *Block, /*Offset=*/0, /*Size=*/0,
50 /*IsCallable=*/false, /*IsLive=*/true);
51 }
52 }
53
54 return jitlink::markAllSymbolsLive(G);
55}
56
57void reassignSectionAddress(jitlink::LinkGraph &LG,
58 const BinarySection &BinSection, uint64_t Address) {
59 auto *JLSection = LG.findSectionByName(Name: BinSection.getSectionID());
60 assert(JLSection && "cannot find section in LinkGraph");
61
62 auto BlockAddress = Address;
63 for (auto *Block : JITLinkLinker::orderedBlocks(Section: *JLSection)) {
64 // FIXME it would seem to make sense to align here. However, in
65 // non-relocation mode, we simply use the original address of functions
66 // which might not be aligned with the minimum alignment used by
67 // BinaryFunction (2). Example failing test when aligning:
68 // bolt/test/X86/addr32.s
69 Block->setAddress(orc::ExecutorAddr(BlockAddress));
70 BlockAddress += Block->getSize();
71 }
72}
73
74} // anonymous namespace
75
76struct JITLinkLinker::Context : jitlink::JITLinkContext {
77 JITLinkLinker &Linker;
78 JITLinkLinker::SectionsMapper MapSections;
79
80 Context(JITLinkLinker &Linker, JITLinkLinker::SectionsMapper MapSections)
81 : JITLinkContext(&Linker.Dylib), Linker(Linker),
82 MapSections(MapSections) {}
83
84 jitlink::JITLinkMemoryManager &getMemoryManager() override {
85 return *Linker.MM;
86 }
87
88 bool shouldAddDefaultTargetPasses(const Triple &TT) const override {
89 // The default passes manipulate DWARF sections in a way incompatible with
90 // BOLT.
91 // TODO check if we can actually use these passes to remove some of the
92 // DWARF manipulation done in BOLT.
93 return false;
94 }
95
96 Error modifyPassConfig(jitlink::LinkGraph &G,
97 jitlink::PassConfiguration &Config) override {
98 Config.PrePrunePasses.push_back(x: markSectionsLive);
99 Config.PostAllocationPasses.push_back(x: [this](auto &G) {
100 MapSections([&G](const BinarySection &Section, uint64_t Address) {
101 reassignSectionAddress(G, Section, Address);
102 });
103 return Error::success();
104 });
105
106 if (G.getTargetTriple().isRISCV()) {
107 Config.PostAllocationPasses.push_back(
108 x: jitlink::createRelaxationPass_ELF_riscv());
109 }
110
111 return Error::success();
112 }
113
114 void notifyFailed(Error Err) override {
115 errs() << "BOLT-ERROR: JITLink failed: " << Err << '\n';
116 exit(status: 1);
117 }
118
119 void
120 lookup(const LookupMap &Symbols,
121 std::unique_ptr<jitlink::JITLinkAsyncLookupContinuation> LC) override {
122 jitlink::AsyncLookupResult AllResults;
123
124 for (const auto &Symbol : Symbols) {
125 std::string SymName = (*Symbol.first).str();
126 LLVM_DEBUG(dbgs() << "BOLT: looking for " << SymName << "\n");
127
128 if (auto SymInfo = Linker.lookupSymbolInfo(Name: SymName)) {
129 LLVM_DEBUG(dbgs() << "Resolved to address 0x"
130 << Twine::utohexstr(SymInfo->Address) << "\n");
131 AllResults[Symbol.first] = orc::ExecutorSymbolDef(
132 orc::ExecutorAddr(SymInfo->Address), JITSymbolFlags());
133 continue;
134 }
135
136 if (const BinaryData *I = Linker.BC.getBinaryDataByName(Name: SymName)) {
137 uint64_t Address = I->isMoved() && !I->isJumpTable()
138 ? I->getOutputAddress()
139 : I->getAddress();
140 LLVM_DEBUG(dbgs() << "Resolved to address 0x"
141 << Twine::utohexstr(Address) << "\n");
142 AllResults[Symbol.first] = orc::ExecutorSymbolDef(
143 orc::ExecutorAddr(Address), JITSymbolFlags());
144 continue;
145 }
146
147 if (Linker.BC.isGOTSymbol(SymName)) {
148 if (const BinaryData *I = Linker.BC.getGOTSymbol()) {
149 uint64_t Address =
150 I->isMoved() ? I->getOutputAddress() : I->getAddress();
151 LLVM_DEBUG(dbgs() << "Resolved to address 0x"
152 << Twine::utohexstr(Address) << "\n");
153 AllResults[Symbol.first] = orc::ExecutorSymbolDef(
154 orc::ExecutorAddr(Address), JITSymbolFlags());
155 continue;
156 }
157 }
158
159 LLVM_DEBUG(dbgs() << "Resolved to address 0x0\n");
160 AllResults[Symbol.first] =
161 orc::ExecutorSymbolDef(orc::ExecutorAddr(0), JITSymbolFlags());
162 }
163
164 LC->run(LR: std::move(AllResults));
165 }
166
167 Error notifyResolved(jitlink::LinkGraph &G) override {
168 for (auto *Symbol : G.defined_symbols()) {
169 SymbolInfo Info{.Address: Symbol->getAddress().getValue(), .Size: Symbol->getSize()};
170 auto Name =
171 Symbol->hasName() ? (*Symbol->getName()).str() : std::string();
172 Linker.Symtab.insert(KV: {std::move(Name), Info});
173 }
174
175 return Error::success();
176 }
177
178 void notifyFinalized(
179 jitlink::JITLinkMemoryManager::FinalizedAlloc Alloc) override {
180 if (Alloc)
181 Linker.Allocs.push_back(x: std::move(Alloc));
182 ++Linker.MM->ObjectsLoaded;
183 }
184};
185
186JITLinkLinker::JITLinkLinker(BinaryContext &BC,
187 std::unique_ptr<ExecutableFileMemoryManager> MM)
188 : BC(BC), MM(std::move(MM)) {}
189
190JITLinkLinker::~JITLinkLinker() { cantFail(Err: MM->deallocate(Allocs: std::move(Allocs))); }
191
192void JITLinkLinker::loadObject(MemoryBufferRef Obj,
193 SectionsMapper MapSections) {
194 auto LG = jitlink::createLinkGraphFromObject(ObjectBuffer: Obj, SSP: BC.getSymbolStringPool());
195 if (auto E = LG.takeError()) {
196 errs() << "BOLT-ERROR: JITLink failed: " << E << '\n';
197 exit(status: 1);
198 }
199
200 if ((*LG)->getTargetTriple().getArch() != BC.TheTriple->getArch()) {
201 errs() << "BOLT-ERROR: linking object with arch "
202 << (*LG)->getTargetTriple().getArchName()
203 << " into context with arch " << BC.TheTriple->getArchName() << "\n";
204 exit(status: 1);
205 }
206
207 auto Ctx = std::make_unique<Context>(args&: *this, args&: MapSections);
208 jitlink::link(G: std::move(*LG), Ctx: std::move(Ctx));
209}
210
211std::optional<JITLinkLinker::SymbolInfo>
212JITLinkLinker::lookupSymbolInfo(StringRef Name) const {
213 auto It = Symtab.find(Key: Name.data());
214 if (It == Symtab.end())
215 return std::nullopt;
216
217 return It->second;
218}
219
220SmallVector<jitlink::Block *, 2>
221JITLinkLinker::orderedBlocks(const jitlink::Section &Section) {
222 SmallVector<jitlink::Block *, 2> Blocks(Section.blocks());
223 llvm::sort(C&: Blocks, Comp: [](const auto *LHS, const auto *RHS) {
224 return LHS->getAddress() < RHS->getAddress();
225 });
226 return Blocks;
227}
228
229size_t JITLinkLinker::sectionSize(const jitlink::Section &Section) {
230 size_t Size = 0;
231
232 for (const auto *Block : orderedBlocks(Section)) {
233 Size = jitlink::alignToBlock(Addr: Size, B: *Block);
234 Size += Block->getSize();
235 }
236
237 return Size;
238}
239
240} // namespace bolt
241} // namespace llvm
242

Provided by KDAB

Privacy Policy
Improve your Profiling and Debugging skills
Find out more

source code of bolt/lib/Rewrite/JITLinkLinker.cpp