1 //===- bolt/Rewrite/JITLinkLinker.cpp - BOLTLinker using JITLink ----------===//
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 #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"
19 #define DEBUG_TYPE "bolt"
26 bool hasSymbols(const jitlink::Block
&B
) {
27 return llvm::any_of(B
.getSection().symbols(),
28 [&B
](const auto &S
) { return &S
->getBlock() == &B
; });
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.
34 Error
markSectionsLive(jitlink::LinkGraph
&G
) {
35 for (auto &Section
: G
.sections()) {
36 // We only need allocatable sections.
37 if (Section
.getMemLifetime() == orc::MemLifetime::NoAlloc
)
40 // Skip empty sections.
41 if (JITLinkLinker::sectionSize(Section
) == 0)
44 for (auto *Block
: Section
.blocks()) {
45 // No need to add symbols if it already has some.
46 if (hasSymbols(*Block
))
49 G
.addAnonymousSymbol(*Block
, /*Offset=*/0, /*Size=*/0,
50 /*IsCallable=*/false, /*IsLive=*/true);
54 return jitlink::markAllSymbolsLive(G
);
57 void reassignSectionAddress(jitlink::LinkGraph
&LG
,
58 const BinarySection
&BinSection
, uint64_t Address
) {
59 auto *JLSection
= LG
.findSectionByName(BinSection
.getSectionID());
60 assert(JLSection
&& "cannot find section in LinkGraph");
62 auto BlockAddress
= Address
;
63 for (auto *Block
: JITLinkLinker::orderedBlocks(*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();
74 } // anonymous namespace
76 struct JITLinkLinker::Context
: jitlink::JITLinkContext
{
77 JITLinkLinker
&Linker
;
78 JITLinkLinker::SectionsMapper MapSections
;
80 Context(JITLinkLinker
&Linker
, JITLinkLinker::SectionsMapper MapSections
)
81 : JITLinkContext(&Linker
.Dylib
), Linker(Linker
),
82 MapSections(MapSections
) {}
84 jitlink::JITLinkMemoryManager
&getMemoryManager() override
{
88 bool shouldAddDefaultTargetPasses(const Triple
&TT
) const override
{
89 // The default passes manipulate DWARF sections in a way incompatible with
91 // TODO check if we can actually use these passes to remove some of the
92 // DWARF manipulation done in BOLT.
96 Error
modifyPassConfig(jitlink::LinkGraph
&G
,
97 jitlink::PassConfiguration
&Config
) override
{
98 Config
.PrePrunePasses
.push_back(markSectionsLive
);
99 Config
.PostAllocationPasses
.push_back([this](auto &G
) {
100 MapSections([&G
](const BinarySection
&Section
, uint64_t Address
) {
101 reassignSectionAddress(G
, Section
, Address
);
103 return Error::success();
106 if (G
.getTargetTriple().isRISCV()) {
107 Config
.PostAllocationPasses
.push_back(
108 jitlink::createRelaxationPass_ELF_riscv());
111 return Error::success();
114 void notifyFailed(Error Err
) override
{
115 errs() << "BOLT-ERROR: JITLink failed: " << Err
<< '\n';
120 lookup(const LookupMap
&Symbols
,
121 std::unique_ptr
<jitlink::JITLinkAsyncLookupContinuation
> LC
) override
{
122 jitlink::AsyncLookupResult AllResults
;
124 for (const auto &Symbol
: Symbols
) {
125 std::string SymName
= Symbol
.first
.str();
126 LLVM_DEBUG(dbgs() << "BOLT: looking for " << SymName
<< "\n");
128 if (auto Address
= Linker
.lookupSymbol(SymName
)) {
129 LLVM_DEBUG(dbgs() << "Resolved to address 0x"
130 << Twine::utohexstr(*Address
) << "\n");
131 AllResults
[Symbol
.first
] = orc::ExecutorSymbolDef(
132 orc::ExecutorAddr(*Address
), JITSymbolFlags());
136 if (const BinaryData
*I
= Linker
.BC
.getBinaryDataByName(SymName
)) {
137 uint64_t Address
= I
->isMoved() && !I
->isJumpTable()
138 ? I
->getOutputAddress()
140 LLVM_DEBUG(dbgs() << "Resolved to address 0x"
141 << Twine::utohexstr(Address
) << "\n");
142 AllResults
[Symbol
.first
] = orc::ExecutorSymbolDef(
143 orc::ExecutorAddr(Address
), JITSymbolFlags());
147 if (Linker
.BC
.isGOTSymbol(SymName
)) {
148 if (const BinaryData
*I
= Linker
.BC
.getGOTSymbol()) {
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());
159 LLVM_DEBUG(dbgs() << "Resolved to address 0x0\n");
160 AllResults
[Symbol
.first
] =
161 orc::ExecutorSymbolDef(orc::ExecutorAddr(0), JITSymbolFlags());
164 LC
->run(std::move(AllResults
));
167 Error
notifyResolved(jitlink::LinkGraph
&G
) override
{
168 for (auto *Symbol
: G
.defined_symbols()) {
169 SymbolInfo Info
{Symbol
->getAddress().getValue(), Symbol
->getSize()};
170 Linker
.Symtab
.insert({Symbol
->getName().str(), Info
});
173 return Error::success();
176 void notifyFinalized(
177 jitlink::JITLinkMemoryManager::FinalizedAlloc Alloc
) override
{
179 Linker
.Allocs
.push_back(std::move(Alloc
));
180 ++Linker
.MM
->ObjectsLoaded
;
184 JITLinkLinker::JITLinkLinker(BinaryContext
&BC
,
185 std::unique_ptr
<ExecutableFileMemoryManager
> MM
)
186 : BC(BC
), MM(std::move(MM
)) {}
188 JITLinkLinker::~JITLinkLinker() { cantFail(MM
->deallocate(std::move(Allocs
))); }
190 void JITLinkLinker::loadObject(MemoryBufferRef Obj
,
191 SectionsMapper MapSections
) {
192 auto LG
= jitlink::createLinkGraphFromObject(Obj
);
193 if (auto E
= LG
.takeError()) {
194 errs() << "BOLT-ERROR: JITLink failed: " << E
<< '\n';
198 if ((*LG
)->getTargetTriple().getArch() != BC
.TheTriple
->getArch()) {
199 errs() << "BOLT-ERROR: linking object with arch "
200 << (*LG
)->getTargetTriple().getArchName()
201 << " into context with arch " << BC
.TheTriple
->getArchName() << "\n";
205 auto Ctx
= std::make_unique
<Context
>(*this, MapSections
);
206 jitlink::link(std::move(*LG
), std::move(Ctx
));
209 std::optional
<JITLinkLinker::SymbolInfo
>
210 JITLinkLinker::lookupSymbolInfo(StringRef Name
) const {
211 auto It
= Symtab
.find(Name
.data());
212 if (It
== Symtab
.end())
218 SmallVector
<jitlink::Block
*, 2>
219 JITLinkLinker::orderedBlocks(const jitlink::Section
&Section
) {
220 SmallVector
<jitlink::Block
*, 2> Blocks(Section
.blocks());
221 llvm::sort(Blocks
, [](const auto *LHS
, const auto *RHS
) {
222 return LHS
->getAddress() < RHS
->getAddress();
227 size_t JITLinkLinker::sectionSize(const jitlink::Section
&Section
) {
230 for (const auto *Block
: orderedBlocks(Section
)) {
231 Size
= jitlink::alignToBlock(Size
, *Block
);
232 Size
+= Block
->getSize();