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