brintos

brintos / llvm-project-archived public Read only

0
0
Text · 9.7 KiB · 8e0f6fb Raw
291 lines · cpp
1//===--------- ELF_x86.cpp - JIT linker implementation for ELF/x86 --------===//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// ELF/x86 jit-link implementation.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ExecutionEngine/JITLink/ELF_x86.h"14#include "DefineExternalSectionStartAndEndSymbols.h"15#include "ELFLinkGraphBuilder.h"16#include "JITLinkGeneric.h"17#include "llvm/BinaryFormat/ELF.h"18#include "llvm/ExecutionEngine/JITLink/x86.h"19#include "llvm/Object/ELFObjectFile.h"20 21#define DEBUG_TYPE "jitlink"22 23using namespace llvm;24using namespace llvm::jitlink;25 26namespace {27constexpr StringRef ELFGOTSymbolName = "_GLOBAL_OFFSET_TABLE_";28 29Error buildTables_ELF_x86(LinkGraph &G) {30  LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");31 32  x86::GOTTableManager GOT;33  x86::PLTTableManager PLT(GOT);34  visitExistingEdges(G, GOT, PLT);35  return Error::success();36}37} // namespace38 39namespace llvm::jitlink {40 41class ELFJITLinker_x86 : public JITLinker<ELFJITLinker_x86> {42  friend class JITLinker<ELFJITLinker_x86>;43 44public:45  ELFJITLinker_x86(std::unique_ptr<JITLinkContext> Ctx,46                   std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)47      : JITLinker(std::move(Ctx), std::move(G), std::move(PassConfig)) {48    getPassConfig().PostAllocationPasses.push_back(49        [this](LinkGraph &G) { return getOrCreateGOTSymbol(G); });50  }51 52private:53  Symbol *GOTSymbol = nullptr;54 55  Error getOrCreateGOTSymbol(LinkGraph &G) {56    auto DefineExternalGOTSymbolIfPresent =57        createDefineExternalSectionStartAndEndSymbolsPass(58            [&](LinkGraph &LG, Symbol &Sym) -> SectionRangeSymbolDesc {59              if (Sym.getName() != nullptr &&60                  *Sym.getName() == ELFGOTSymbolName)61                if (auto *GOTSection = G.findSectionByName(62                        x86::GOTTableManager::getSectionName())) {63                  GOTSymbol = &Sym;64                  return {*GOTSection, true};65                }66              return {};67            });68 69    // Try to attach _GLOBAL_OFFSET_TABLE_ to the GOT if it's defined as an70    // external.71    if (auto Err = DefineExternalGOTSymbolIfPresent(G))72      return Err;73 74    // If we succeeded then we're done.75    if (GOTSymbol)76      return Error::success();77 78    // Otherwise look for a GOT section: If it already has a start symbol we'll79    // record it, otherwise we'll create our own.80    // If there's a GOT section but we didn't find an external GOT symbol...81    if (auto *GOTSection =82            G.findSectionByName(x86::GOTTableManager::getSectionName())) {83 84      // Check for an existing defined symbol.85      for (auto *Sym : GOTSection->symbols())86        if (Sym->getName() != nullptr && *Sym->getName() == ELFGOTSymbolName) {87          GOTSymbol = Sym;88          return Error::success();89        }90 91      // If there's no defined symbol then create one.92      SectionRange SR(*GOTSection);93 94      if (SR.empty()) {95        GOTSymbol =96            &G.addAbsoluteSymbol(ELFGOTSymbolName, orc::ExecutorAddr(), 0,97                                 Linkage::Strong, Scope::Local, true);98      } else {99        GOTSymbol =100            &G.addDefinedSymbol(*SR.getFirstBlock(), 0, ELFGOTSymbolName, 0,101                                Linkage::Strong, Scope::Local, false, true);102      }103    }104 105    return Error::success();106  }107 108  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {109    return x86::applyFixup(G, B, E, GOTSymbol);110  }111};112 113class ELFLinkGraphBuilder_x86 : public ELFLinkGraphBuilder<object::ELF32LE> {114private:115  using ELFT = object::ELF32LE;116 117  Expected<x86::EdgeKind_x86> getRelocationKind(const uint32_t Type) {118    switch (Type) {119    case ELF::R_386_32:120      return x86::Pointer32;121    case ELF::R_386_PC32:122      return x86::PCRel32;123    case ELF::R_386_16:124      return x86::Pointer16;125    case ELF::R_386_PC16:126      return x86::PCRel16;127    case ELF::R_386_GOT32:128      return x86::RequestGOTAndTransformToDelta32FromGOT;129    case ELF::R_386_GOT32X:130      // TODO: Add a relaxable edge kind and update relaxation optimization.131      return x86::RequestGOTAndTransformToDelta32FromGOT;132    case ELF::R_386_GOTPC:133      return x86::Delta32;134    case ELF::R_386_GOTOFF:135      return x86::Delta32FromGOT;136    case ELF::R_386_PLT32:137      return x86::BranchPCRel32;138    }139 140    return make_error<JITLinkError>(141        "In " + G->getName() + ": Unsupported x86 relocation type " +142        object::getELFRelocationTypeName(ELF::EM_386, Type));143  }144 145  Error addRelocations() override {146    LLVM_DEBUG(dbgs() << "Adding relocations\n");147    using Base = ELFLinkGraphBuilder<ELFT>;148    using Self = ELFLinkGraphBuilder_x86;149 150    for (const auto &RelSect : Base::Sections) {151      // Validate the section to read relocation entries from.152      if (RelSect.sh_type == ELF::SHT_RELA)153        return make_error<StringError>(154            "No SHT_RELA in valid x86 ELF object files",155            inconvertibleErrorCode());156 157      if (Error Err = Base::forEachRelRelocation(RelSect, this,158                                                 &Self::addSingleRelocation))159        return Err;160    }161 162    return Error::success();163  }164 165  Error addSingleRelocation(const typename ELFT::Rel &Rel,166                            const typename ELFT::Shdr &FixupSection,167                            Block &BlockToFix) {168    using Base = ELFLinkGraphBuilder<ELFT>;169 170    auto ELFReloc = Rel.getType(false);171 172    // R_386_NONE is a no-op.173    if (LLVM_UNLIKELY(ELFReloc == ELF::R_386_NONE))174      return Error::success();175 176    uint32_t SymbolIndex = Rel.getSymbol(false);177    auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);178    if (!ObjSymbol)179      return ObjSymbol.takeError();180 181    Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);182    if (!GraphSymbol)183      return make_error<StringError>(184          formatv("Could not find symbol at given index, did you add it to "185                  "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",186                  SymbolIndex, (*ObjSymbol)->st_shndx,187                  Base::GraphSymbols.size()),188          inconvertibleErrorCode());189 190    Expected<x86::EdgeKind_x86> Kind = getRelocationKind(ELFReloc);191    if (!Kind)192      return Kind.takeError();193 194    auto FixupAddress = orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;195    int64_t Addend = 0;196 197    switch (*Kind) {198    case x86::Pointer32:199    case x86::PCRel32:200    case x86::RequestGOTAndTransformToDelta32FromGOT:201    case x86::Delta32:202    case x86::Delta32FromGOT:203    case x86::BranchPCRel32:204    case x86::BranchPCRel32ToPtrJumpStub:205    case x86::BranchPCRel32ToPtrJumpStubBypassable: {206      const char *FixupContent = BlockToFix.getContent().data() +207                                 (FixupAddress - BlockToFix.getAddress());208      Addend = *(const support::little32_t *)FixupContent;209      break;210    }211    case x86::Pointer16:212    case x86::PCRel16: {213      const char *FixupContent = BlockToFix.getContent().data() +214                                 (FixupAddress - BlockToFix.getAddress());215      Addend = *(const support::little16_t *)FixupContent;216      break;217    }218    }219 220    Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();221    Edge GE(*Kind, Offset, *GraphSymbol, Addend);222    LLVM_DEBUG({223      dbgs() << "    ";224      printEdge(dbgs(), BlockToFix, GE, x86::getEdgeKindName(*Kind));225      dbgs() << "\n";226    });227 228    BlockToFix.addEdge(std::move(GE));229    return Error::success();230  }231 232public:233  ELFLinkGraphBuilder_x86(StringRef FileName, const object::ELFFile<ELFT> &Obj,234                          std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT,235                          SubtargetFeatures Features)236      : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),237                                  std::move(Features), FileName,238                                  x86::getEdgeKindName) {}239};240 241Expected<std::unique_ptr<LinkGraph>>242createLinkGraphFromELFObject_x86(MemoryBufferRef ObjectBuffer,243                                 std::shared_ptr<orc::SymbolStringPool> SSP) {244  LLVM_DEBUG({245    dbgs() << "Building jitlink graph for new input "246           << ObjectBuffer.getBufferIdentifier() << "...\n";247  });248 249  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);250  if (!ELFObj)251    return ELFObj.takeError();252 253  auto Features = (*ELFObj)->getFeatures();254  if (!Features)255    return Features.takeError();256 257  assert((*ELFObj)->getArch() == Triple::x86 &&258         "Only x86 (little endian) is supported for now");259 260  auto &ELFObjFile = cast<object::ELFObjectFile<object::ELF32LE>>(**ELFObj);261 262  return ELFLinkGraphBuilder_x86((*ELFObj)->getFileName(),263                                 ELFObjFile.getELFFile(), std::move(SSP),264                                 (*ELFObj)->makeTriple(), std::move(*Features))265      .buildGraph();266}267 268void link_ELF_x86(std::unique_ptr<LinkGraph> G,269                  std::unique_ptr<JITLinkContext> Ctx) {270  PassConfiguration Config;271  const Triple &TT = G->getTargetTriple();272  if (Ctx->shouldAddDefaultTargetPasses(TT)) {273    if (auto MarkLive = Ctx->getMarkLivePass(TT))274      Config.PrePrunePasses.push_back(std::move(MarkLive));275    else276      Config.PrePrunePasses.push_back(markAllSymbolsLive);277 278    // Add an in-place GOT and PLT build pass.279    Config.PostPrunePasses.push_back(buildTables_ELF_x86);280 281    // Add GOT/Stubs optimizer pass.282    Config.PreFixupPasses.push_back(x86::optimizeGOTAndStubAccesses);283  }284  if (auto Err = Ctx->modifyPassConfig(*G, Config))285    return Ctx->notifyFailed(std::move(Err));286 287  ELFJITLinker_x86::link(std::move(Ctx), std::move(G), std::move(Config));288}289 290} // namespace llvm::jitlink291