| 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-exception |
| 6 | // |
| 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 | |
| 25 | namespace { |
| 26 | |
| 27 | using namespace llvm; |
| 28 | using namespace llvm::jitlink; |
| 29 | |
| 30 | constexpr StringRef ELFTOCSymbolName = ".TOC." ; |
| 31 | constexpr StringRef TOCSymbolAliasIdent = "__TOC__" ; |
| 32 | constexpr uint64_t ELFTOCBaseOffset = 0x8000; |
| 33 | constexpr StringRef ELFTLSInfoSectionName = "$__TLSINFO" ; |
| 34 | |
| 35 | template <llvm::endianness Endianness> |
| 36 | class TLSInfoTableManager_ELF_ppc64 |
| 37 | : public TableManager<TLSInfoTableManager_ELF_ppc64<Endianness>> { |
| 38 | public: |
| 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 by |
| 65 | // `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(Content&: TLSInfoEntry, Offset: 0, Size: 16, IsCallable: false, IsLive: false); |
| 71 | } |
| 72 | |
| 73 | private: |
| 74 | Section &getTLSInfoSection(LinkGraph &G) { |
| 75 | if (!TLSInfoTable) |
| 76 | TLSInfoTable = |
| 77 | &G.createSection(Name: ELFTLSInfoSectionName, Prot: 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 | |
| 89 | template <> |
| 90 | const 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 | |
| 96 | template <> |
| 97 | const 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 | |
| 103 | template <llvm::endianness Endianness> |
| 104 | Symbol &(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(Name: ELFTOCSymbolName, Size: 0, IsWeaklyReferenced: false); |
| 124 | |
| 125 | return TOC.getEntryForTarget(G, *TOCSymbol); |
| 126 | } |
| 127 | |
| 128 | // Register preexisting GOT entries with TOC table manager. |
| 129 | template <llvm::endianness Endianness> |
| 130 | inline void |
| 131 | registerExistingGOTEntries(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(Name: ".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(Content&: *B, Offset: E.getOffset(), |
| 142 | Size: G.getPointerSize(), |
| 143 | IsCallable: false, IsLive: false)); |
| 144 | } |
| 145 | } |
| 146 | |
| 147 | template <llvm::endianness Endianness> |
| 148 | Error 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 TOC |
| 152 | // base as ELFABIv2 suggests: |
| 153 | // > The GOT consists of an 8-byte header that contains the TOC base (the |
| 154 | // first TOC base when multiple TOCs are present), followed by an array of |
| 155 | // 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 the |
| 166 | // synthesized section. |
| 167 | // Merge sections included in TOC into synthesized TOC section, |
| 168 | // thus TOC is compact and reducing chances of relocation |
| 169 | // overflow. |
| 170 | if (Section *TOCSection = G.findSectionByName(Name: TOC.getSectionName())) { |
| 171 | // .got and .plt are not normally present in a relocatable object file |
| 172 | // because they are linker generated. |
| 173 | if (Section *gotSection = G.findSectionByName(Name: ".got" )) |
| 174 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *gotSection); |
| 175 | if (Section *tocSection = G.findSectionByName(Name: ".toc" )) |
| 176 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *tocSection); |
| 177 | if (Section *sdataSection = G.findSectionByName(Name: ".sdata" )) |
| 178 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *sdataSection); |
| 179 | if (Section *sbssSection = G.findSectionByName(Name: ".sbss" )) |
| 180 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *sbssSection); |
| 181 | // .tocbss no longer appears in ELFABIv2. Leave it here to be compatible |
| 182 | // with rtdyld. |
| 183 | if (Section *tocbssSection = G.findSectionByName(Name: ".tocbss" )) |
| 184 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *tocbssSection); |
| 185 | if (Section *pltSection = G.findSectionByName(Name: ".plt" )) |
| 186 | G.mergeSections(DstSection&: *TOCSection, SrcSection&: *pltSection); |
| 187 | } |
| 188 | |
| 189 | return Error::success(); |
| 190 | } |
| 191 | |
| 192 | } // namespace |
| 193 | |
| 194 | namespace llvm::jitlink { |
| 195 | |
| 196 | template <llvm::endianness Endianness> |
| 197 | class ELFLinkGraphBuilder_ppc64 |
| 198 | : public ELFLinkGraphBuilder<object::ELFType<Endianness, true>> { |
| 199 | private: |
| 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>(Args: "Local-dynamic TLS model is not supported" , |
| 240 | Args: 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>(Args: "Local-exec TLS model is not supported" , |
| 248 | Args: 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(Machine: ELF::EM_PPC64, Type: 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 finally |
| 364 | // turns out to be an external call, we'll have a stub for the external |
| 365 | // target, the target of this edge will be the stub and its addend will be |
| 366 | // set 0. |
| 367 | Addend += ELF::decodePPC64LocalEntryOffset(Other: (*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(E: std::move(GE)); |
| 391 | return Error::success(); |
| 392 | } |
| 393 | |
| 394 | public: |
| 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 | |
| 404 | template <llvm::endianness Endianness> |
| 405 | class ELFJITLinker_ppc64 : public JITLinker<ELFJITLinker_ppc64<Endianness>> { |
| 406 | using JITLinkerBase = JITLinker<ELFJITLinker_ppc64<Endianness>>; |
| 407 | friend JITLinkerBase; |
| 408 | |
| 409 | public: |
| 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 | |
| 417 | private: |
| 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 | Name: 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(Sym&: *TOCSymbol, Address: TOCBaseAddr); |
| 450 | // Create an alias of .TOC. so that rtdyld checker can recognize. |
| 451 | G.addAbsoluteSymbol(Name: TOCSymbolAliasIdent, Address: TOCSymbol->getAddress(), |
| 452 | Size: TOCSymbol->getSize(), L: TOCSymbol->getLinkage(), |
| 453 | S: TOCSymbol->getScope(), IsLive: TOCSymbol->isLive()); |
| 454 | return Error::success(); |
| 455 | } |
| 456 | |
| 457 | // If TOC section doesn't exist, which means no TOC relocation is found, we |
| 458 | // 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 | |
| 467 | template <llvm::endianness Endianness> |
| 468 | Expected<std::unique_ptr<LinkGraph>> |
| 469 | createLinkGraphFromELFObject_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(Object: 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 | |
| 492 | template <llvm::endianness Endianness> |
| 493 | void link_ELF_ppc64(std::unique_ptr<LinkGraph> G, |
| 494 | std::unique_ptr<JITLinkContext> Ctx) { |
| 495 | PassConfiguration Config; |
| 496 | |
| 497 | if (Ctx->shouldAddDefaultTargetPasses(TT: G->getTargetTriple())) { |
| 498 | // Construct a JITLinker and run the link function. |
| 499 | |
| 500 | // Add eh-frame passes. |
| 501 | Config.PrePrunePasses.push_back(x: DWARFRecordSectionSplitter(".eh_frame" )); |
| 502 | Config.PrePrunePasses.push_back(x: EHFrameEdgeFixer( |
| 503 | ".eh_frame" , G->getPointerSize(), ppc64::Pointer32, ppc64::Pointer64, |
| 504 | ppc64::Delta32, ppc64::Delta64, ppc64::NegDelta32)); |
| 505 | Config.PrePrunePasses.push_back(x: EHFrameNullTerminator(".eh_frame" )); |
| 506 | |
| 507 | // Add a mark-live pass. |
| 508 | if (auto MarkLive = Ctx->getMarkLivePass(TT: G->getTargetTriple())) |
| 509 | Config.PrePrunePasses.push_back(x: std::move(MarkLive)); |
| 510 | else |
| 511 | Config.PrePrunePasses.push_back(x: markAllSymbolsLive); |
| 512 | } |
| 513 | |
| 514 | Config.PostPrunePasses.push_back(buildTables_ELF_ppc64<Endianness>); |
| 515 | |
| 516 | if (auto Err = Ctx->modifyPassConfig(G&: *G, Config)) |
| 517 | return Ctx->notifyFailed(Err: std::move(Err)); |
| 518 | |
| 519 | ELFJITLinker_ppc64<Endianness>::link(std::move(Ctx), std::move(G), |
| 520 | std::move(Config)); |
| 521 | } |
| 522 | |
| 523 | Expected<std::unique_ptr<LinkGraph>> |
| 524 | createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer, |
| 525 | std::shared_ptr<orc::SymbolStringPool> SSP) { |
| 526 | return createLinkGraphFromELFObject_ppc64<llvm::endianness::big>( |
| 527 | ObjectBuffer: std::move(ObjectBuffer), SSP: std::move(SSP)); |
| 528 | } |
| 529 | |
| 530 | Expected<std::unique_ptr<LinkGraph>> createLinkGraphFromELFObject_ppc64le( |
| 531 | MemoryBufferRef ObjectBuffer, std::shared_ptr<orc::SymbolStringPool> SSP) { |
| 532 | return createLinkGraphFromELFObject_ppc64<llvm::endianness::little>( |
| 533 | ObjectBuffer: std::move(ObjectBuffer), SSP: std::move(SSP)); |
| 534 | } |
| 535 | |
| 536 | /// jit-link the given object buffer, which must be a ELF ppc64 object file. |
| 537 | void link_ELF_ppc64(std::unique_ptr<LinkGraph> G, |
| 538 | std::unique_ptr<JITLinkContext> Ctx) { |
| 539 | return link_ELF_ppc64<llvm::endianness::big>(G: std::move(G), Ctx: std::move(Ctx)); |
| 540 | } |
| 541 | |
| 542 | /// jit-link the given object buffer, which must be a ELF ppc64le object file. |
| 543 | void link_ELF_ppc64le(std::unique_ptr<LinkGraph> G, |
| 544 | std::unique_ptr<JITLinkContext> Ctx) { |
| 545 | return link_ELF_ppc64<llvm::endianness::little>(G: std::move(G), Ctx: std::move(Ctx)); |
| 546 | } |
| 547 | |
| 548 | } // end namespace llvm::jitlink |
| 549 | |