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 Kind = ppc64::RequestCallNoTOC; 221 break; 222 case ELF::R_PPC64_REL24: 223 Kind = ppc64::RequestCall; 224 assert(Addend == 0 && "Addend is expected to be 0 for a function call"); 225 // We assume branching to local entry, will reverse the addend if not. 226 Addend = ELF::decodePPC64LocalEntryOffset((*ObjSymbol)->st_other); 227 break; 228 case ELF::R_PPC64_REL64: 229 Kind = ppc64::Delta64; 230 break; 231 } 232 233 Edge GE(Kind, Offset, *GraphSymbol, Addend); 234 BlockToFix.addEdge(std::move(GE)); 235 return Error::success(); 236 } 237 238 public: 239 ELFLinkGraphBuilder_ppc64(StringRef FileName, 240 const object::ELFFile<ELFT> &Obj, Triple TT, 241 SubtargetFeatures Features) 242 : ELFLinkGraphBuilder<ELFT>(Obj, std::move(TT), std::move(Features), 243 FileName, ppc64::getEdgeKindName) {} 244 }; 245 246 template <support::endianness Endianness> 247 class ELFJITLinker_ppc64 : public JITLinker<ELFJITLinker_ppc64<Endianness>> { 248 using JITLinkerBase = JITLinker<ELFJITLinker_ppc64<Endianness>>; 249 friend JITLinkerBase; 250 251 public: 252 ELFJITLinker_ppc64(std::unique_ptr<JITLinkContext> Ctx, 253 std::unique_ptr<LinkGraph> G, PassConfiguration PassConfig) 254 : JITLinkerBase(std::move(Ctx), std::move(G), std::move(PassConfig)) { 255 JITLinkerBase::getPassConfig().PostAllocationPasses.push_back( 256 [this](LinkGraph &G) { return defineTOCBase(G); }); 257 } 258 259 private: 260 Symbol *TOCSymbol = nullptr; 261 262 Error defineTOCBase(LinkGraph &G) { 263 for (Symbol *Sym : G.defined_symbols()) { 264 if (LLVM_UNLIKELY(Sym->getName() == ELFTOCSymbolName)) { 265 TOCSymbol = Sym; 266 return Error::success(); 267 } 268 } 269 270 assert(TOCSymbol == nullptr && 271 "TOCSymbol should not be defined at this point"); 272 273 for (Symbol *Sym : G.external_symbols()) { 274 if (Sym->getName() == ELFTOCSymbolName) { 275 TOCSymbol = Sym; 276 break; 277 } 278 } 279 280 if (Section *TOCSection = G.findSectionByName( 281 ppc64::TOCTableManager<Endianness>::getSectionName())) { 282 assert(!TOCSection->empty() && "TOC section should have reserved an " 283 "entry for containing the TOC base"); 284 285 SectionRange SR(*TOCSection); 286 orc::ExecutorAddr TOCBaseAddr(SR.getFirstBlock()->getAddress() + 287 ELFTOCBaseOffset); 288 assert(TOCSymbol && TOCSymbol->isExternal() && 289 ".TOC. should be a external symbol at this point"); 290 G.makeAbsolute(*TOCSymbol, TOCBaseAddr); 291 // Create an alias of .TOC. so that rtdyld checker can recognize. 292 G.addAbsoluteSymbol(TOCSymbolAliasIdent, TOCSymbol->getAddress(), 293 TOCSymbol->getSize(), TOCSymbol->getLinkage(), 294 TOCSymbol->getScope(), TOCSymbol->isLive()); 295 return Error::success(); 296 } 297 298 // If TOC section doesn't exist, which means no TOC relocation is found, we 299 // don't need a TOCSymbol. 300 return Error::success(); 301 } 302 303 Error applyFixup(LinkGraph &G, Block &B, const Edge &E) const { 304 return ppc64::applyFixup<Endianness>(G, B, E, TOCSymbol); 305 } 306 }; 307 308 template <support::endianness Endianness> 309 Expected<std::unique_ptr<LinkGraph>> 310 createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer) { 311 LLVM_DEBUG({ 312 dbgs() << "Building jitlink graph for new input " 313 << ObjectBuffer.getBufferIdentifier() << "...\n"; 314 }); 315 316 auto ELFObj = object::ObjectFile::createELFObjectFile(ObjectBuffer); 317 if (!ELFObj) 318 return ELFObj.takeError(); 319 320 auto Features = (*ELFObj)->getFeatures(); 321 if (!Features) 322 return Features.takeError(); 323 324 using ELFT = object::ELFType<Endianness, true>; 325 auto &ELFObjFile = cast<object::ELFObjectFile<ELFT>>(**ELFObj); 326 return ELFLinkGraphBuilder_ppc64<Endianness>( 327 (*ELFObj)->getFileName(), ELFObjFile.getELFFile(), 328 (*ELFObj)->makeTriple(), std::move(*Features)) 329 .buildGraph(); 330 } 331 332 template <support::endianness Endianness> 333 void link_ELF_ppc64(std::unique_ptr<LinkGraph> G, 334 std::unique_ptr<JITLinkContext> Ctx) { 335 PassConfiguration Config; 336 337 if (Ctx->shouldAddDefaultTargetPasses(G->getTargetTriple())) { 338 // Construct a JITLinker and run the link function. 339 340 // Add eh-frame passses. 341 Config.PrePrunePasses.push_back(DWARFRecordSectionSplitter(".eh_frame")); 342 Config.PrePrunePasses.push_back(EHFrameEdgeFixer( 343 ".eh_frame", G->getPointerSize(), ppc64::Pointer32, ppc64::Pointer64, 344 ppc64::Delta32, ppc64::Delta64, ppc64::NegDelta32)); 345 Config.PrePrunePasses.push_back(EHFrameNullTerminator(".eh_frame")); 346 347 // Add a mark-live pass. 348 if (auto MarkLive = Ctx->getMarkLivePass(G->getTargetTriple())) 349 Config.PrePrunePasses.push_back(std::move(MarkLive)); 350 else 351 Config.PrePrunePasses.push_back(markAllSymbolsLive); 352 } 353 354 Config.PostPrunePasses.push_back(buildTables_ELF_ppc64<Endianness>); 355 356 if (auto Err = Ctx->modifyPassConfig(*G, Config)) 357 return Ctx->notifyFailed(std::move(Err)); 358 359 ELFJITLinker_ppc64<Endianness>::link(std::move(Ctx), std::move(G), 360 std::move(Config)); 361 } 362 363 Expected<std::unique_ptr<LinkGraph>> 364 createLinkGraphFromELFObject_ppc64(MemoryBufferRef ObjectBuffer) { 365 return createLinkGraphFromELFObject_ppc64<support::big>( 366 std::move(ObjectBuffer)); 367 } 368 369 Expected<std::unique_ptr<LinkGraph>> 370 createLinkGraphFromELFObject_ppc64le(MemoryBufferRef ObjectBuffer) { 371 return createLinkGraphFromELFObject_ppc64<support::little>( 372 std::move(ObjectBuffer)); 373 } 374 375 /// jit-link the given object buffer, which must be a ELF ppc64 object file. 376 void link_ELF_ppc64(std::unique_ptr<LinkGraph> G, 377 std::unique_ptr<JITLinkContext> Ctx) { 378 return link_ELF_ppc64<support::big>(std::move(G), std::move(Ctx)); 379 } 380 381 /// jit-link the given object buffer, which must be a ELF ppc64le object file. 382 void link_ELF_ppc64le(std::unique_ptr<LinkGraph> G, 383 std::unique_ptr<JITLinkContext> Ctx) { 384 return link_ELF_ppc64<support::little>(std::move(G), std::move(Ctx)); 385 } 386 387 } // end namespace llvm::jitlink 388