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