brintos

brintos / llvm-project-archived public Read only

0
0
Text · 19.3 KiB · 83b51eb Raw
549 lines · cpp
1//===------- ELF_ppc64.cpp -JIT linker implementation for ELF/ppc64 -------===//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/ppc64 jit-link implementation.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/ExecutionEngine/JITLink/ELF_ppc64.h"14#include "llvm/ExecutionEngine/JITLink/DWARFRecordSectionSplitter.h"15#include "llvm/ExecutionEngine/JITLink/TableManager.h"16#include "llvm/ExecutionEngine/JITLink/ppc64.h"17#include "llvm/Object/ELFObjectFile.h"18 19#include "EHFrameSupportImpl.h"20#include "ELFLinkGraphBuilder.h"21#include "JITLinkGeneric.h"22 23#define DEBUG_TYPE "jitlink"24 25namespace {26 27using namespace llvm;28using namespace llvm::jitlink;29 30constexpr StringRef ELFTOCSymbolName = ".TOC.";31constexpr StringRef TOCSymbolAliasIdent = "__TOC__";32constexpr uint64_t ELFTOCBaseOffset = 0x8000;33constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO";34 35template <llvm::endianness Endianness>36class TLSInfoTableManager_ELF_ppc6437    : public TableManager<TLSInfoTableManager_ELF_ppc64<Endianness>> {38public:39  static const uint8_t TLSInfoEntryContent[16];40 41  static StringRef getSectionName() { return ELFTLSInfoSectionName; }42 43  bool visitEdge(LinkGraph &G, Block *B, Edge &E) {44    Edge::Kind K = E.getKind();45    switch (K) {46    case ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16HA:47      E.setKind(ppc64::TOCDelta16HA);48      E.setTarget(this->getEntryForTarget(G, E.getTarget()));49      return true;50    case ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO:51      E.setKind(ppc64::TOCDelta16LO);52      E.setTarget(this->getEntryForTarget(G, E.getTarget()));53      return true;54    case ppc64::RequestTLSDescInGOTAndTransformToDelta34:55      E.setKind(ppc64::Delta34);56      E.setTarget(this->getEntryForTarget(G, E.getTarget()));57      return true;58    default:59      return false;60    }61  }62 63  Symbol &createEntry(LinkGraph &G, Symbol &Target) {64    // The TLS Info entry's key value will be written by65    // `fixTLVSectionsAndEdges`, so create mutable content.66    auto &TLSInfoEntry = G.createMutableContentBlock(67        getTLSInfoSection(G), G.allocateContent(getTLSInfoEntryContent()),68        orc::ExecutorAddr(), 8, 0);69    TLSInfoEntry.addEdge(ppc64::Pointer64, 8, Target, 0);70    return G.addAnonymousSymbol(TLSInfoEntry, 0, 16, false, false);71  }72 73private:74  Section &getTLSInfoSection(LinkGraph &G) {75    if (!TLSInfoTable)76      TLSInfoTable =77          &G.createSection(ELFTLSInfoSectionName, orc::MemProt::Read);78    return *TLSInfoTable;79  }80 81  ArrayRef<char> getTLSInfoEntryContent() const {82    return {reinterpret_cast<const char *>(TLSInfoEntryContent),83            sizeof(TLSInfoEntryContent)};84  }85 86  Section *TLSInfoTable = nullptr;87};88 89template <>90const uint8_t TLSInfoTableManager_ELF_ppc64<91    llvm::endianness::little>::TLSInfoEntryContent[16] = {92    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */93    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /*data address*/94};95 96template <>97const uint8_t TLSInfoTableManager_ELF_ppc64<98    llvm::endianness::big>::TLSInfoEntryContent[16] = {99    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /*pthread key */100    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00  /*data address*/101};102 103template <llvm::endianness Endianness>104Symbol &createELFGOTHeader(LinkGraph &G,105                           ppc64::TOCTableManager<Endianness> &TOC) {106  Symbol *TOCSymbol = nullptr;107 108  for (Symbol *Sym : G.defined_symbols())109    if (LLVM_UNLIKELY(Sym->hasName() && *Sym->getName() == ELFTOCSymbolName)) {110      TOCSymbol = Sym;111      break;112    }113 114  if (LLVM_LIKELY(TOCSymbol == nullptr)) {115    for (Symbol *Sym : G.external_symbols())116      if (Sym->hasName() && *Sym->getName() == ELFTOCSymbolName) {117        TOCSymbol = Sym;118        break;119      }120  }121 122  if (!TOCSymbol)123    TOCSymbol = &G.addExternalSymbol(ELFTOCSymbolName, 0, false);124 125  return TOC.getEntryForTarget(G, *TOCSymbol);126}127 128// Register preexisting GOT entries with TOC table manager.129template <llvm::endianness Endianness>130inline void131registerExistingGOTEntries(LinkGraph &G,132                           ppc64::TOCTableManager<Endianness> &TOC) {133  auto isGOTEntry = [](const Edge &E) {134    return E.getKind() == ppc64::Pointer64 && E.getTarget().isExternal();135  };136  if (Section *dotTOCSection = G.findSectionByName(".toc")) {137    for (Block *B : dotTOCSection->blocks())138      for (Edge &E : B->edges())139        if (isGOTEntry(E))140          TOC.registerPreExistingEntry(E.getTarget(),141                                       G.addAnonymousSymbol(*B, E.getOffset(),142                                                            G.getPointerSize(),143                                                            false, false));144  }145}146 147template <llvm::endianness Endianness>148Error buildTables_ELF_ppc64(LinkGraph &G) {149  LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n");150  ppc64::TOCTableManager<Endianness> TOC;151  // Before visiting edges, we create a header containing the address of TOC152  // base as ELFABIv2 suggests:153  //  > The GOT consists of an 8-byte header that contains the TOC base (the154  //  first TOC base when multiple TOCs are present), followed by an array of155  //  8-byte addresses.156  createELFGOTHeader(G, TOC);157 158  // There might be compiler-generated GOT entries in ELF relocatable file.159  registerExistingGOTEntries(G, TOC);160 161  ppc64::PLTTableManager<Endianness> PLT(TOC);162  TLSInfoTableManager_ELF_ppc64<Endianness> TLSInfo;163  visitExistingEdges(G, TOC, PLT, TLSInfo);164 165  // After visiting edges in LinkGraph, we have GOT entries built in the166  // synthesized section.167  // Merge sections included in TOC into synthesized TOC section,168  // thus TOC is compact and reducing chances of relocation169  // overflow.170  if (Section *TOCSection = G.findSectionByName(TOC.getSectionName())) {171    // .got and .plt are not normally present in a relocatable object file172    // because they are linker generated.173    if (Section *gotSection = G.findSectionByName(".got"))174      G.mergeSections(*TOCSection, *gotSection);175    if (Section *tocSection = G.findSectionByName(".toc"))176      G.mergeSections(*TOCSection, *tocSection);177    if (Section *sdataSection = G.findSectionByName(".sdata"))178      G.mergeSections(*TOCSection, *sdataSection);179    if (Section *sbssSection = G.findSectionByName(".sbss"))180      G.mergeSections(*TOCSection, *sbssSection);181    // .tocbss no longer appears in ELFABIv2. Leave it here to be compatible182    // with rtdyld.183    if (Section *tocbssSection = G.findSectionByName(".tocbss"))184      G.mergeSections(*TOCSection, *tocbssSection);185    if (Section *pltSection = G.findSectionByName(".plt"))186      G.mergeSections(*TOCSection, *pltSection);187  }188 189  return Error::success();190}191 192} // namespace193 194namespace llvm::jitlink {195 196template <llvm::endianness Endianness>197class ELFLinkGraphBuilder_ppc64198    : public ELFLinkGraphBuilder<object::ELFType<Endianness, true>> {199private:200  using ELFT = object::ELFType<Endianness, true>;201  using Base = ELFLinkGraphBuilder<ELFT>;202 203  using Base::G; // Use LinkGraph pointer from base class.204 205  Error addRelocations() override {206    LLVM_DEBUG(dbgs() << "Processing relocations:\n");207 208    using Self = ELFLinkGraphBuilder_ppc64<Endianness>;209    for (const auto &RelSect : Base::Sections) {210      // Validate the section to read relocation entries from.211      if (RelSect.sh_type == ELF::SHT_REL)212        return make_error<StringError>("No SHT_REL in valid " +213                                           G->getTargetTriple().getArchName() +214                                           " ELF object files",215                                       inconvertibleErrorCode());216 217      if (Error Err = Base::forEachRelaRelocation(RelSect, this,218                                                  &Self::addSingleRelocation))219        return Err;220    }221 222    return Error::success();223  }224 225  Error addSingleRelocation(const typename ELFT::Rela &Rel,226                            const typename ELFT::Shdr &FixupSection,227                            Block &BlockToFix) {228    using Base = ELFLinkGraphBuilder<ELFT>;229    auto ELFReloc = Rel.getType(false);230 231    // R_PPC64_NONE is a no-op.232    if (LLVM_UNLIKELY(ELFReloc == ELF::R_PPC64_NONE))233      return Error::success();234 235    // TLS model markers. We only support global-dynamic model now.236    if (ELFReloc == ELF::R_PPC64_TLSGD)237      return Error::success();238    if (ELFReloc == ELF::R_PPC64_TLSLD)239      return make_error<StringError>("Local-dynamic TLS model is not supported",240                                     inconvertibleErrorCode());241 242    if (ELFReloc == ELF::R_PPC64_PCREL_OPT)243      // TODO: Support PCREL optimization, now ignore it.244      return Error::success();245 246    if (ELFReloc == ELF::R_PPC64_TPREL34)247      return make_error<StringError>("Local-exec TLS model is not supported",248                                     inconvertibleErrorCode());249 250    auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec);251    if (!ObjSymbol)252      return ObjSymbol.takeError();253 254    uint32_t SymbolIndex = Rel.getSymbol(false);255    Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex);256    if (!GraphSymbol)257      return make_error<StringError>(258          formatv("Could not find symbol at given index, did you add it to "259                  "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}",260                  SymbolIndex, (*ObjSymbol)->st_shndx,261                  Base::GraphSymbols.size()),262          inconvertibleErrorCode());263 264    int64_t Addend = Rel.r_addend;265    orc::ExecutorAddr FixupAddress =266        orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset;267    Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress();268    Edge::Kind Kind = Edge::Invalid;269 270    switch (ELFReloc) {271    default:272      return make_error<JITLinkError>(273          "In " + G->getName() + ": Unsupported ppc64 relocation type " +274          object::getELFRelocationTypeName(ELF::EM_PPC64, ELFReloc));275    case ELF::R_PPC64_ADDR64:276      Kind = ppc64::Pointer64;277      break;278    case ELF::R_PPC64_ADDR32:279      Kind = ppc64::Pointer32;280      break;281    case ELF::R_PPC64_ADDR16:282      Kind = ppc64::Pointer16;283      break;284    case ELF::R_PPC64_ADDR16_DS:285      Kind = ppc64::Pointer16DS;286      break;287    case ELF::R_PPC64_ADDR16_HA:288      Kind = ppc64::Pointer16HA;289      break;290    case ELF::R_PPC64_ADDR16_HI:291      Kind = ppc64::Pointer16HI;292      break;293    case ELF::R_PPC64_ADDR16_HIGH:294      Kind = ppc64::Pointer16HIGH;295      break;296    case ELF::R_PPC64_ADDR16_HIGHA:297      Kind = ppc64::Pointer16HIGHA;298      break;299    case ELF::R_PPC64_ADDR16_HIGHER:300      Kind = ppc64::Pointer16HIGHER;301      break;302    case ELF::R_PPC64_ADDR16_HIGHERA:303      Kind = ppc64::Pointer16HIGHERA;304      break;305    case ELF::R_PPC64_ADDR16_HIGHEST:306      Kind = ppc64::Pointer16HIGHEST;307      break;308    case ELF::R_PPC64_ADDR16_HIGHESTA:309      Kind = ppc64::Pointer16HIGHESTA;310      break;311    case ELF::R_PPC64_ADDR16_LO:312      Kind = ppc64::Pointer16LO;313      break;314    case ELF::R_PPC64_ADDR16_LO_DS:315      Kind = ppc64::Pointer16LODS;316      break;317    case ELF::R_PPC64_ADDR14:318      Kind = ppc64::Pointer14;319      break;320    case ELF::R_PPC64_TOC:321      Kind = ppc64::TOC;322      break;323    case ELF::R_PPC64_TOC16:324      Kind = ppc64::TOCDelta16;325      break;326    case ELF::R_PPC64_TOC16_HA:327      Kind = ppc64::TOCDelta16HA;328      break;329    case ELF::R_PPC64_TOC16_HI:330      Kind = ppc64::TOCDelta16HI;331      break;332    case ELF::R_PPC64_TOC16_DS:333      Kind = ppc64::TOCDelta16DS;334      break;335    case ELF::R_PPC64_TOC16_LO:336      Kind = ppc64::TOCDelta16LO;337      break;338    case ELF::R_PPC64_TOC16_LO_DS:339      Kind = ppc64::TOCDelta16LODS;340      break;341    case ELF::R_PPC64_REL16:342      Kind = ppc64::Delta16;343      break;344    case ELF::R_PPC64_REL16_HA:345      Kind = ppc64::Delta16HA;346      break;347    case ELF::R_PPC64_REL16_HI:348      Kind = ppc64::Delta16HI;349      break;350    case ELF::R_PPC64_REL16_LO:351      Kind = ppc64::Delta16LO;352      break;353    case ELF::R_PPC64_REL32:354      Kind = ppc64::Delta32;355      break;356    case ELF::R_PPC64_REL24_NOTOC:357      Kind = ppc64::RequestCallNoTOC;358      break;359    case ELF::R_PPC64_REL24:360      Kind = ppc64::RequestCall;361      // Determining a target is external or not is deferred in PostPrunePass.362      // We assume branching to local entry by default, since in PostPrunePass,363      // we don't have any context to determine LocalEntryOffset. If it finally364      // turns out to be an external call, we'll have a stub for the external365      // target, the target of this edge will be the stub and its addend will be366      // set 0.367      Addend += ELF::decodePPC64LocalEntryOffset((*ObjSymbol)->st_other);368      break;369    case ELF::R_PPC64_REL64:370      Kind = ppc64::Delta64;371      break;372    case ELF::R_PPC64_PCREL34:373      Kind = ppc64::Delta34;374      break;375    case ELF::R_PPC64_GOT_PCREL34:376      Kind = ppc64::RequestGOTAndTransformToDelta34;377      break;378    case ELF::R_PPC64_GOT_TLSGD16_HA:379      Kind = ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16HA;380      break;381    case ELF::R_PPC64_GOT_TLSGD16_LO:382      Kind = ppc64::RequestTLSDescInGOTAndTransformToTOCDelta16LO;383      break;384    case ELF::R_PPC64_GOT_TLSGD_PCREL34:385      Kind = ppc64::RequestTLSDescInGOTAndTransformToDelta34;386      break;387    }388 389    Edge GE(Kind, Offset, *GraphSymbol, Addend);390    BlockToFix.addEdge(std::move(GE));391    return Error::success();392  }393 394public:395  ELFLinkGraphBuilder_ppc64(StringRef FileName,396                            const object::ELFFile<ELFT> &Obj,397                            std::shared_ptr<orc::SymbolStringPool> SSP,398                            Triple TT, SubtargetFeatures Features)399      : ELFLinkGraphBuilder<ELFT>(Obj, std::move(SSP), std::move(TT),400                                  std::move(Features), FileName,401                                  ppc64::getEdgeKindName) {}402};403 404template <llvm::endianness Endianness>405class ELFJITLinker_ppc64 : public JITLinker<ELFJITLinker_ppc64<Endianness>> {406  using JITLinkerBase = JITLinker<ELFJITLinker_ppc64<Endianness>>;407  friend JITLinkerBase;408 409public:410  ELFJITLinker_ppc64(std::unique_ptr<JITLinkContext> Ctx,411                     std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig)412      : JITLinkerBase(std::move(Ctx), std::move(G), std::move(PassConfig)) {413    JITLinkerBase::getPassConfig().PostAllocationPasses.push_back(414        [this](LinkGraph &G) { return defineTOCBase(G); });415  }416 417private:418  Symbol *TOCSymbol = nullptr;419 420  Error defineTOCBase(LinkGraph &G) {421    for (Symbol *Sym : G.defined_symbols()) {422      if (LLVM_UNLIKELY(Sym->hasName() &&423                        *Sym->getName() == ELFTOCSymbolName)) {424        TOCSymbol = Sym;425        return Error::success();426      }427    }428 429    assert(TOCSymbol == nullptr &&430           "TOCSymbol should not be defined at this point");431 432    for (Symbol *Sym : G.external_symbols()) {433      if (Sym->hasName() && *Sym->getName() == ELFTOCSymbolName) {434        TOCSymbol = Sym;435        break;436      }437    }438 439    if (Section *TOCSection = G.findSectionByName(440            ppc64::TOCTableManager<Endianness>::getSectionName())) {441      assert(!TOCSection->empty() && "TOC section should have reserved an "442                                     "entry for containing the TOC base");443 444      SectionRange SR(*TOCSection);445      orc::ExecutorAddr TOCBaseAddr(SR.getFirstBlock()->getAddress() +446                                    ELFTOCBaseOffset);447      assert(TOCSymbol && TOCSymbol->isExternal() &&448             ".TOC. should be a external symbol at this point");449      G.makeAbsolute(*TOCSymbol, TOCBaseAddr);450      // Create an alias of .TOC. so that rtdyld checker can recognize.451      G.addAbsoluteSymbol(TOCSymbolAliasIdent, TOCSymbol->getAddress(),452                          TOCSymbol->getSize(), TOCSymbol->getLinkage(),453                          TOCSymbol->getScope(), TOCSymbol->isLive());454      return Error::success();455    }456 457    // If TOC section doesn't exist, which means no TOC relocation is found, we458    // don't need a TOCSymbol.459    return Error::success();460  }461 462  Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const {463    return ppc64::applyFixup<Endianness>(G, B, E, TOCSymbol);464  }465};466 467template <llvm::endianness Endianness>468Expected<std::unique_ptr<LinkGraph>>469createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer,470                                   std::shared_ptr<orc::SymbolStringPool> SSP) {471  LLVM_DEBUG({472    dbgs() << "Building jitlink graph for new input "473           << ObjectBuffer.getBufferIdentifier() << "...\n";474  });475 476  auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer);477  if (!ELFObj)478    return ELFObj.takeError();479 480  auto Features = (*ELFObj)->getFeatures();481  if (!Features)482    return Features.takeError();483 484  using ELFT = object::ELFType<Endianness, true>;485  auto &ELFObjFile = cast<object::ELFObjectFile<ELFT>>(**ELFObj);486  return ELFLinkGraphBuilder_ppc64<Endianness>(487             (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), std::move(SSP),488             (*ELFObj)->makeTriple(), std::move(*Features))489      .buildGraph();490}491 492template <llvm::endianness Endianness>493void link_ELF_ppc64(std::unique_ptr<LinkGraph> G,494                    std::unique_ptr<JITLinkContext> Ctx) {495  PassConfiguration Config;496 497  if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) {498    // Construct a JITLinker and run the link function.499 500    // Add eh-frame passes.501    Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame"));502    Config.PrePrunePasses.push_back(EHFrameEdgeFixer(503        ".eh_frame", G->getPointerSize(), ppc64::Pointer32, ppc64::Pointer64,504        ppc64::Delta32, ppc64::Delta64, ppc64::NegDelta32));505    Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame"));506 507    // Add a mark-live pass.508    if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple()))509      Config.PrePrunePasses.push_back(std::move(MarkLive));510    else511      Config.PrePrunePasses.push_back(markAllSymbolsLive);512  }513 514  Config.PostPrunePasses.push_back(buildTables_ELF_ppc64<Endianness>);515 516  if (auto Err = Ctx->modifyPassConfig(*G, Config))517    return Ctx->notifyFailed(std::move(Err));518 519  ELFJITLinker_ppc64<Endianness>::link(std::move(Ctx), std::move(G),520                                       std::move(Config));521}522 523Expected<std::unique_ptr<LinkGraph>>524createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer,525                                   std::shared_ptr<orc::SymbolStringPool> SSP) {526  return createLinkGraphFromELFObject_ppc64<llvm::endianness::big>(527      std::move(ObjectBuffer), std::move(SSP));528}529 530Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_ppc64le(531    MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) {532  return createLinkGraphFromELFObject_ppc64<llvm::endianness::little>(533      std::move(ObjectBuffer), std::move(SSP));534}535 536/// jit-link the given object buffer, which must be a ELF ppc64 object file.537void link_ELF_ppc64(std::unique_ptr<LinkGraph> G,538                    std::unique_ptr<JITLinkContext> Ctx) {539  return link_ELF_ppc64<llvm::endianness::big>(std::move(G), std::move(Ctx));540}541 542/// jit-link the given object buffer, which must be a ELF ppc64le object file.543void link_ELF_ppc64le(std::unique_ptr<LinkGraph> G,544                      std::unique_ptr<JITLinkContext> Ctx) {545  return link_ELF_ppc64<llvm::endianness::little>(std::move(G), std::move(Ctx));546}547 548} // end namespace llvm::jitlink549