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 21 namespace llvm { 22 namespace bolt { 23 24 namespace { 25 26 bool hasSymbols(const jitlink::Block &B) { 27 return llvm::any_of(B.getSection().symbols(), 28 [&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. 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) 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(*Block)) 47 continue; 48 49 G.addAnonymousSymbol(*Block, /*Offset=*/0, /*Size=*/0, 50 /*IsCallable=*/false, /*IsLive=*/true); 51 } 52 } 53 54 return jitlink::markAllSymbolsLive(G); 55 } 56 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"); 61 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(); 71 } 72 } 73 74 } // anonymous namespace 75 76 struct 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(markSectionsLive); 99 Config.PostAllocationPasses.push_back([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 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(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 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()); 133 continue; 134 } 135 136 if (const BinaryData *I = Linker.BC.getBinaryDataByName(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(std::move(AllResults)); 165 } 166 167 Error notifyResolved(jitlink::LinkGraph &G) override { 168 for (auto *Symbol : G.defined_symbols()) { 169 SymbolInfo Info{Symbol->getAddress().getValue(), Symbol->getSize()}; 170 auto Name = 171 Symbol->hasName() ? (*Symbol->getName()).str() : std::string(); 172 Linker.Symtab.insert({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(std::move(Alloc)); 182 ++Linker.MM->ObjectsLoaded; 183 } 184 }; 185 186 JITLinkLinker::JITLinkLinker(BinaryContext &BC, 187 std::unique_ptr<ExecutableFileMemoryManager> MM) 188 : BC(BC), MM(std::move(MM)) {} 189 190 JITLinkLinker::~JITLinkLinker() { cantFail(MM->deallocate(std::move(Allocs))); } 191 192 void JITLinkLinker::loadObject(MemoryBufferRef Obj, 193 SectionsMapper MapSections) { 194 auto LG = jitlink::createLinkGraphFromObject(Obj, BC.getSymbolStringPool()); 195 if (auto E = LG.takeError()) { 196 errs() << "BOLT-ERROR: JITLink failed: " << E << '\n'; 197 exit(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(1); 205 } 206 207 auto Ctx = std::make_unique<Context>(*this, MapSections); 208 jitlink::link(std::move(*LG), std::move(Ctx)); 209 } 210 211 std::optional<JITLinkLinker::SymbolInfo> 212 JITLinkLinker::lookupSymbolInfo(StringRef Name) const { 213 auto It = Symtab.find(Name.data()); 214 if (It == Symtab.end()) 215 return std::nullopt; 216 217 return It->second; 218 } 219 220 SmallVector<jitlink::Block *, 2> 221 JITLinkLinker::orderedBlocks(const jitlink::Section &Section) { 222 SmallVector<jitlink::Block *, 2> Blocks(Section.blocks()); 223 llvm::sort(Blocks, [](const auto *LHS, const auto *RHS) { 224 return LHS->getAddress() < RHS->getAddress(); 225 }); 226 return Blocks; 227 } 228 229 size_t JITLinkLinker::sectionSize(const jitlink::Section &Section) { 230 size_t Size = 0; 231 232 for (const auto *Block : orderedBlocks(Section)) { 233 Size = jitlink::alignToBlock(Size, *Block); 234 Size += Block->getSize(); 235 } 236 237 return Size; 238 } 239 240 } // namespace bolt 241 } // namespace llvm 242