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 #include "llvm/Support/Endian.h" 19 20 #include "EHFrameSupportImpl.h" 21 #include "ELFLinkGraphBuilder.h" 22 #include "JITLinkGeneric.h" 23 24 #define DEBUG_TYPE "jitlink" 25 26 namespace { 27 28 using namespace llvm; 29 using namespace llvm::jitlink; 30 31 constexpr StringRef ELFTOCSymbolName = ".TOC."; 32 constexpr StringRef TOCSymbolAliasIdent = "__TOC__"; 33 constexpr uint64_t ELFTOCBaseOffset = 0x8000; 34 35 template <support::endianness Endianness> 36 Symbol &createELFGOTHeader(LinkGraph &G, 37 ppc64::TOCTableManager<Endianness> &TOC) { 38 Symbol *TOCSymbol = nullptr; 39 40 for (Symbol *Sym : G.defined_symbols()) 41 if (LLVM_UNLIKELY(Sym->getName() == ELFTOCSymbolName)) { 42 TOCSymbol = Sym; 43 break; 44 } 45 46 if (LLVM_LIKELY(TOCSymbol == nullptr)) { 47 for (Symbol *Sym : G.external_symbols()) 48 if (Sym->getName() == ELFTOCSymbolName) { 49 TOCSymbol = Sym; 50 break; 51 } 52 } 53 54 if (!TOCSymbol) 55 TOCSymbol = &G.addExternalSymbol(ELFTOCSymbolName, 0, false); 56 57 return TOC.getEntryForTarget(G, *TOCSymbol); 58 } 59 60 // Register preexisting GOT entries with TOC table manager. 61 template <support::endianness Endianness> 62 inline void 63 registerExistingGOTEntries(LinkGraph &G, 64 ppc64::TOCTableManager<Endianness> &TOC) { 65 auto isGOTEntry = [](const Edge &E) { 66 return E.getKind() == ppc64::Pointer64 && E.getTarget().isExternal(); 67 }; 68 if (Section *dotTOCSection = G.findSectionByName(".toc")) { 69 for (Block *B : dotTOCSection->blocks()) 70 for (Edge &E : B->edges()) 71 if (isGOTEntry(E)) 72 TOC.registerPreExistingEntry(E.getTarget(), 73 G.addAnonymousSymbol(*B, E.getOffset(), 74 G.getPointerSize(), 75 false, false)); 76 } 77 } 78 79 template <support::endianness Endianness> 80 Error buildTables_ELF_ppc64(LinkGraph &G) { 81 LLVM_DEBUG(dbgs() << "Visiting edges in graph:\n"); 82 ppc64::TOCTableManager<Endianness> TOC; 83 // Before visiting edges, we create a header containing the address of TOC 84 // base as ELFABIv2 suggests: 85 // > The GOT consists of an 8-byte header that contains the TOC base (the 86 // first TOC base when multiple TOCs are present), followed by an array of 87 // 8-byte addresses. 88 createELFGOTHeader(G, TOC); 89 90 // There might be compiler-generated GOT entries in ELF relocatable file. 91 registerExistingGOTEntries(G, TOC); 92 93 ppc64::PLTTableManager<Endianness> PLT(TOC); 94 visitExistingEdges(G, TOC, PLT); 95 // TODO: Add TLS support. 96 97 // After visiting edges in LinkGraph, we have GOT entries built in the 98 // synthesized section. 99 // Merge sections included in TOC into synthesized TOC section, 100 // thus TOC is compact and reducing chances of relocation 101 // overflow. 102 if (Section *TOCSection = G.findSectionByName(TOC.getSectionName())) { 103 // .got and .plt are not normally present in a relocatable object file 104 // because they are linker generated. 105 if (Section *gotSection = G.findSectionByName(".got")) 106 G.mergeSections(*TOCSection, *gotSection); 107 if (Section *tocSection = G.findSectionByName(".toc")) 108 G.mergeSections(*TOCSection, *tocSection); 109 if (Section *sdataSection = G.findSectionByName(".sdata")) 110 G.mergeSections(*TOCSection, *sdataSection); 111 if (Section *sbssSection = G.findSectionByName(".sbss")) 112 G.mergeSections(*TOCSection, *sbssSection); 113 // .tocbss no longer appears in ELFABIv2. Leave it here to be compatible 114 // with rtdyld. 115 if (Section *tocbssSection = G.findSectionByName(".tocbss")) 116 G.mergeSections(*TOCSection, *tocbssSection); 117 if (Section *pltSection = G.findSectionByName(".plt")) 118 G.mergeSections(*TOCSection, *pltSection); 119 } 120 121 return Error::success(); 122 } 123 124 } // namespace 125 126 namespace llvm::jitlink { 127 128 template <support::endianness Endianness> 129 class ELFLinkGraphBuilder_ppc64 130 : public ELFLinkGraphBuilder<object::ELFType<Endianness, true>> { 131 private: 132 using ELFT = object::ELFType<Endianness, true>; 133 using Base = ELFLinkGraphBuilder<ELFT>; 134 135 using Base::G; // Use LinkGraph pointer from base class. 136 137 Error addRelocations() override { 138 LLVM_DEBUG(dbgs() << "Processing relocations:\n"); 139 140 using Self = ELFLinkGraphBuilder_ppc64<Endianness>; 141 for (const auto &RelSect : Base::Sections) { 142 // Validate the section to read relocation entries from. 143 if (RelSect.sh_type == ELF::SHT_REL) 144 return make_error<StringError>("No SHT_REL in valid " + 145 G->getTargetTriple().getArchName() + 146 " ELF object files", 147 inconvertibleErrorCode()); 148 149 if (Error Err = Base::forEachRelaRelocation(RelSect, this, 150 &Self::addSingleRelocation)) 151 return Err; 152 } 153 154 return Error::success(); 155 } 156 157 Error addSingleRelocation(const typename ELFT::Rela &Rel, 158 const typename ELFT::Shdr &FixupSection, 159 Block &BlockToFix) { 160 using Base = ELFLinkGraphBuilder<ELFT>; 161 auto ELFReloc = Rel.getType(false); 162 163 // R_PPC64_NONE is a no-op. 164 if (LLVM_UNLIKELY(ELFReloc == ELF::R_PPC64_NONE)) 165 return Error::success(); 166 167 auto ObjSymbol = Base::Obj.getRelocationSymbol(Rel, Base::SymTabSec); 168 if (!ObjSymbol) 169 return ObjSymbol.takeError(); 170 171 uint32_t SymbolIndex = Rel.getSymbol(false); 172 Symbol *GraphSymbol = Base::getGraphSymbol(SymbolIndex); 173 if (!GraphSymbol) 174 return make_error<StringError>( 175 formatv("Could not find symbol at given index, did you add it to " 176 "JITSymbolTable? index: {0}, shndx: {1} Size of table: {2}", 177 SymbolIndex, (*ObjSymbol)->st_shndx, 178 Base::GraphSymbols.size()), 179 inconvertibleErrorCode()); 180 181 int64_t Addend = Rel.r_addend; 182 orc::ExecutorAddr FixupAddress = 183 orc::ExecutorAddr(FixupSection.sh_addr) + Rel.r_offset; 184 Edge::OffsetT Offset = FixupAddress - BlockToFix.getAddress(); 185 Edge::Kind Kind = Edge::Invalid; 186 187 switch (ELFReloc) { 188 default: 189 return make_error<JITLinkError>( 190 "In " + G->getName() + ": Unsupported ppc64 relocation type " + 191 object::getELFRelocationTypeName(ELF::EM_PPC64, ELFReloc)); 192 case ELF::R_PPC64_ADDR64: 193 Kind = ppc64::Pointer64; 194 break; 195 case ELF::R_PPC64_TOC16_HA: 196 Kind = ppc64::TOCDelta16HA; 197 break; 198 case ELF::R_PPC64_TOC16_DS: 199 Kind = ppc64::TOCDelta16DS; 200 break; 201 case ELF::R_PPC64_TOC16_LO: 202 Kind = ppc64::TOCDelta16LO; 203 break; 204 case ELF::R_PPC64_TOC16_LO_DS: 205 Kind = ppc64::TOCDelta16LODS; 206 break; 207 case ELF::R_PPC64_REL16: 208 Kind = ppc64::Delta16; 209 break; 210 case ELF::R_PPC64_REL16_HA: 211 Kind = ppc64::Delta16HA; 212 break; 213 case ELF::R_PPC64_REL16_LO: 214 Kind = ppc64::Delta16LO; 215 break; 216 case ELF::R_PPC64_REL32: 217 Kind = ppc64::Delta32; 218 break; 219 case ELF::R_PPC64_REL24_NOTOC: 220 case ELF::R_PPC64_REL24: { 221 bool isLocal = !GraphSymbol->isExternal(); 222 if (isLocal) { 223 // TODO: There are cases a local function call need a call stub. 224 // 1. Caller uses TOC, the callee doesn't, need a r2 save stub. 225 // 2. Caller doesn't use TOC, the callee does, need a r12 setup stub. 226 // FIXME: For a local call, we might need a thunk if branch target is 227 // out of range. 228 Kind = ppc64::CallBranchDelta; 229 // Branch to local entry. 230 Addend += ELF::decodePPC64LocalEntryOffset((*ObjSymbol)->st_other); 231 } else { 232 Kind = ELFReloc == ELF::R_PPC64_REL24 ? ppc64::RequestPLTCallStubSaveTOC 233 : ppc64::RequestPLTCallStubNoTOC; 234 } 235 break; 236 } 237 case ELF::R_PPC64_REL64: 238 Kind = ppc64::Delta64; 239 break; 240 } 241 242 Edge GE(Kind, Offset, *GraphSymbol, Addend); 243 BlockToFix.addEdge(std::move(GE)); 244 return Error::success(); 245 } 246 247 public: 248 ELFLinkGraphBuilder_ppc64(StringRef FileName, 249 const object::ELFFile<ELFT> &Obj, Triple TT, 250 SubtargetFeatures Features) 251 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features), 252 FileName, ppc64::getEdgeKindName) {} 253 }; 254 255 template <support::endianness Endianness> 256 class ELFJITLinker_ppc64 : public JITLinker<ELFJITLinker_ppc64<Endianness>> { 257 using JITLinkerBase = JITLinker<ELFJITLinker_ppc64<Endianness>>; 258 friend JITLinkerBase; 259 260 public: 261 ELFJITLinker_ppc64(std::unique_ptr<JITLinkContext> Ctx, 262 std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig) 263 : JITLinkerBase(std::move(Ctx), std::move(G), std::move(PassConfig)) { 264 JITLinkerBase::getPassConfig().PostAllocationPasses.push_back( 265 [this](LinkGraph &G) { return defineTOCBase(G); }); 266 } 267 268 private: 269 Symbol *TOCSymbol = nullptr; 270 271 Error defineTOCBase(LinkGraph &G) { 272 for (Symbol *Sym : G.defined_symbols()) { 273 if (LLVM_UNLIKELY(Sym->getName() == ELFTOCSymbolName)) { 274 TOCSymbol = Sym; 275 return Error::success(); 276 } 277 } 278 279 assert(TOCSymbol == nullptr && 280 "TOCSymbol should not be defined at this point"); 281 282 for (Symbol *Sym : G.external_symbols()) { 283 if (Sym->getName() == ELFTOCSymbolName) { 284 TOCSymbol = Sym; 285 break; 286 } 287 } 288 289 if (Section *TOCSection = G.findSectionByName( 290 ppc64::TOCTableManager<Endianness>::getSectionName())) { 291 assert(!TOCSection->empty() && "TOC section should have reserved an " 292 "entry for containing the TOC base"); 293 294 SectionRange SR(*TOCSection); 295 orc::ExecutorAddr TOCBaseAddr(SR.getFirstBlock()->getAddress() + 296 ELFTOCBaseOffset); 297 assert(TOCSymbol && TOCSymbol->isExternal() && 298 ".TOC. should be a external symbol at this point"); 299 G.makeAbsolute(*TOCSymbol, TOCBaseAddr); 300 // Create an alias of .TOC. so that rtdyld checker can recognize. 301 G.addAbsoluteSymbol(TOCSymbolAliasIdent, TOCSymbol->getAddress(), 302 TOCSymbol->getSize(), TOCSymbol->getLinkage(), 303 TOCSymbol->getScope(), TOCSymbol->isLive()); 304 return Error::success(); 305 } 306 307 // If TOC section doesn't exist, which means no TOC relocation is found, we 308 // don't need a TOCSymbol. 309 return Error::success(); 310 } 311 312 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 313 return ppc64::applyFixup<Endianness>(G, B, E, TOCSymbol); 314 } 315 }; 316 317 template <support::endianness Endianness> 318 Expected<std::unique_ptr<LinkGraph>> 319 createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer) { 320 LLVM_DEBUG({ 321 dbgs() << "Building jitlink graph for new input " 322 << ObjectBuffer.getBufferIdentifier() << "...\n"; 323 }); 324 325 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer); 326 if (!ELFObj) 327 return ELFObj.takeError(); 328 329 auto Features = (*ELFObj)->getFeatures(); 330 if (!Features) 331 return Features.takeError(); 332 333 using ELFT = object::ELFType<Endianness, true>; 334 auto &ELFObjFile = cast<object::ELFObjectFile<ELFT>>(**ELFObj); 335 return ELFLinkGraphBuilder_ppc64<Endianness>( 336 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 337 (*ELFObj)->makeTriple(), std::move(*Features)) 338 .buildGraph(); 339 } 340 341 template <support::endianness Endianness> 342 void link_ELF_ppc64(std::unique_ptr<LinkGraph> G, 343 std::unique_ptr<JITLinkContext> Ctx) { 344 PassConfiguration Config; 345 346 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { 347 // Construct a JITLinker and run the link function. 348 349 // Add eh-frame passses. 350 Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame")); 351 Config.PrePrunePasses.push_back(EHFrameEdgeFixer( 352 ".eh_frame", G->getPointerSize(), ppc64::Pointer32, ppc64::Pointer64, 353 ppc64::Delta32, ppc64::Delta64, ppc64::NegDelta32)); 354 Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame")); 355 356 // Add a mark-live pass. 357 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) 358 Config.PrePrunePasses.push_back(std::move(MarkLive)); 359 else 360 Config.PrePrunePasses.push_back(markAllSymbolsLive); 361 } 362 363 Config.PostPrunePasses.push_back(buildTables_ELF_ppc64<Endianness>); 364 365 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 366 return Ctx->notifyFailed(std::move(Err)); 367 368 ELFJITLinker_ppc64<Endianness>::link(std::move(Ctx), std::move(G), 369 std::move(Config)); 370 } 371 372 Expected<std::unique_ptr<LinkGraph>> 373 createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer) { 374 return createLinkGraphFromELFObject_ppc64<support::big>( 375 std::move(ObjectBuffer)); 376 } 377 378 Expected<std::unique_ptr<LinkGraph>> 379 createLinkGraphFromELFObject_ppc64le(MemoryBufferRef ObjectBuffer) { 380 return createLinkGraphFromELFObject_ppc64<support::little>( 381 std::move(ObjectBuffer)); 382 } 383 384 /// jit-link the given object buffer, which must be a ELF ppc64 object file. 385 void link_ELF_ppc64(std::unique_ptr<LinkGraph> G, 386 std::unique_ptr<JITLinkContext> Ctx) { 387 return link_ELF_ppc64<support::big>(std::move(G), std::move(Ctx)); 388 } 389 390 /// jit-link the given object buffer, which must be a ELF ppc64le object file. 391 void link_ELF_ppc64le(std::unique_ptr<LinkGraph> G, 392 std::unique_ptr<JITLinkContext> Ctx) { 393 return link_ELF_ppc64<support::little>(std::move(G), std::move(Ctx)); 394 } 395 396 } // end namespace llvm::jitlink 397