242 lines · cpp
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-exception6//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(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 contain32/// any symbols will always be pruned. This pass adds anonymous symbols to33/// 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(*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 57void 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, in65 // non-relocation mode, we simply use the original address of functions66 // which might not be aligned with the minimum alignment used by67 // BinaryFunction (2). Example failing test when aligning:68 // bolt/test/X86/addr32.s69 Block->setAddress(orc::ExecutorAddr(BlockAddress));70 BlockAddress += Block->getSize();71 }72}73 74} // anonymous namespace75 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 with90 // BOLT.91 // TODO check if we can actually use these passes to remove some of the92 // 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 void120 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(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(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 186JITLinkLinker::JITLinkLinker(BinaryContext &BC,187 std::unique_ptr<ExecutableFileMemoryManager> MM)188 : BC(BC), MM(std::move(MM)) {}189 190JITLinkLinker::~JITLinkLinker() { cantFail(MM->deallocate(std::move(Allocs))); }191 192void 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 211std::optional<JITLinkLinker::SymbolInfo>212JITLinkLinker::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 220SmallVector<jitlink::Block *, 2>221JITLinkLinker::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 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(Size, *Block);234 Size += Block->getSize();235 }236 237 return Size;238}239 240} // namespace bolt241} // namespace llvm242