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 //===----------------------------------------------------------------------===//
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"
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
)
38 // Skip empty sections.
39 if (JITLinkLinker::sectionSize(Section
) == 0)
42 for (auto *Block
: Section
.blocks()) {
43 // No need to add symbols if it already has some.
44 if (hasSymbols(*Block
))
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
{
86 bool shouldAddDefaultTargetPasses(const Triple
&TT
) const override
{
87 // The default passes manipulate DWARF sections in a way incompatible with
89 // TODO check if we can actually use these passes to remove some of the
90 // DWARF manipulation done in BOLT.
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';
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());
134 if (const BinaryData
*I
= Linker
.BC
.getBinaryDataByName(SymName
)) {
135 uint64_t Address
= I
->isMoved() && !I
->isJumpTable()
136 ? I
->getOutputAddress()
138 LLVM_DEBUG(dbgs() << "Resolved to address 0x"
139 << Twine::utohexstr(Address
) << "\n");
140 AllResults
[Symbol
.first
] = orc::ExecutorSymbolDef(
141 orc::ExecutorAddr(Address
), JITSymbolFlags());
145 if (Linker
.BC
.isGOTSymbol(SymName
)) {
146 if (const BinaryData
*I
= Linker
.BC
.getGOTSymbol()) {
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());
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
{
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';
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";
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())
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();
225 size_t JITLinkLinker::sectionSize(const jitlink::Section
&Section
) {
228 for (const auto *Block
: orderedBlocks(Section
)) {
229 Size
= jitlink::alignToBlock(Size
, *Block
);
230 Size
+= Block
->getSize();