brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.0 KiB · c287dc0 Raw
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