1 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2 // See https://llvm.org/LICENSE.txt for license information. 3 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4 // 5 //===----------------------------------------------------------------------===// 6 // 7 // Generic XCOFF LinkGraph building code. 8 // 9 //===----------------------------------------------------------------------===// 10 11 #include "XCOFFLinkGraphBuilder.h" 12 #include "llvm/ADT/STLExtras.h" 13 #include "llvm/BinaryFormat/XCOFF.h" 14 #include "llvm/ExecutionEngine/JITLink/JITLink.h" 15 #include "llvm/ExecutionEngine/JITLink/ppc64.h" 16 #include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h" 17 #include "llvm/ExecutionEngine/Orc/Shared/MemoryFlags.h" 18 #include "llvm/Object/ObjectFile.h" 19 #include "llvm/Object/XCOFFObjectFile.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/Error.h" 22 #include "llvm/Support/Format.h" 23 #include "llvm/Support/raw_ostream.h" 24 #include <memory> 25 26 using namespace llvm; 27 28 #define DEBUG_TYPE "jitlink" 29 30 namespace llvm { 31 namespace jitlink { 32 33 XCOFFLinkGraphBuilder::XCOFFLinkGraphBuilder( 34 const object::XCOFFObjectFile &Obj, 35 std::shared_ptr<orc::SymbolStringPool> SSP, Triple TT, 36 SubtargetFeatures Features, 37 LinkGraph::GetEdgeKindNameFunction GetEdgeKindName) 38 : Obj(Obj), 39 G(std::make_unique<LinkGraph>( 40 std::string(Obj.getFileName()), std::move(SSP), std::move(TT), 41 std::move(Features), std::move(GetEdgeKindName))) {} 42 43 #ifndef NDEBUG 44 static llvm::StringRef getStorageClassString(XCOFF::StorageClass SC) { 45 switch (SC) { 46 case XCOFF::StorageClass::C_FILE: 47 return "C_FILE (File name)"; 48 case XCOFF::StorageClass::C_BINCL: 49 return "C_BINCL (Beginning of include file)"; 50 case XCOFF::StorageClass::C_EINCL: 51 return "C_EINCL (Ending of include file)"; 52 case XCOFF::StorageClass::C_GSYM: 53 return "C_GSYM (Global variable)"; 54 case XCOFF::StorageClass::C_STSYM: 55 return "C_STSYM (Statically allocated symbol)"; 56 case XCOFF::StorageClass::C_BCOMM: 57 return "C_BCOMM (Beginning of common block)"; 58 case XCOFF::StorageClass::C_ECOMM: 59 return "C_ECOMM (End of common block)"; 60 case XCOFF::StorageClass::C_ENTRY: 61 return "C_ENTRY (Alternate entry)"; 62 case XCOFF::StorageClass::C_BSTAT: 63 return "C_BSTAT (Beginning of static block)"; 64 case XCOFF::StorageClass::C_ESTAT: 65 return "C_ESTAT (End of static block)"; 66 case XCOFF::StorageClass::C_GTLS: 67 return "C_GTLS (Global thread-local variable)"; 68 case XCOFF::StorageClass::C_STTLS: 69 return "C_STTLS (Static thread-local variable)"; 70 case XCOFF::StorageClass::C_DWARF: 71 return "C_DWARF (DWARF section symbol)"; 72 case XCOFF::StorageClass::C_LSYM: 73 return "C_LSYM (Automatic variable allocated on stack)"; 74 case XCOFF::StorageClass::C_PSYM: 75 return "C_PSYM (Argument to subroutine allocated on stack)"; 76 case XCOFF::StorageClass::C_RSYM: 77 return "C_RSYM (Register variable)"; 78 case XCOFF::StorageClass::C_RPSYM: 79 return "C_RPSYM (Argument to function stored in register)"; 80 case XCOFF::StorageClass::C_ECOML: 81 return "C_ECOML (Local member of common block)"; 82 case XCOFF::StorageClass::C_FUN: 83 return "C_FUN (Function or procedure)"; 84 case XCOFF::StorageClass::C_EXT: 85 return "C_EXT (External symbol)"; 86 case XCOFF::StorageClass::C_WEAKEXT: 87 return "C_WEAKEXT (Weak external symbol)"; 88 case XCOFF::StorageClass::C_NULL: 89 return "C_NULL"; 90 case XCOFF::StorageClass::C_STAT: 91 return "C_STAT (Static)"; 92 case XCOFF::StorageClass::C_BLOCK: 93 return "C_BLOCK (\".bb\" or \".eb\")"; 94 case XCOFF::StorageClass::C_FCN: 95 return "C_FCN (\".bf\" or \".ef\")"; 96 case XCOFF::StorageClass::C_HIDEXT: 97 return "C_HIDEXT (Un-named external symbol)"; 98 case XCOFF::StorageClass::C_INFO: 99 return "C_INFO (Comment string in .info section)"; 100 case XCOFF::StorageClass::C_DECL: 101 return "C_DECL (Declaration of object)"; 102 case XCOFF::StorageClass::C_AUTO: 103 return "C_AUTO (Automatic variable)"; 104 case XCOFF::StorageClass::C_REG: 105 return "C_REG (Register variable)"; 106 case XCOFF::StorageClass::C_EXTDEF: 107 return "C_EXTDEF (External definition)"; 108 case XCOFF::StorageClass::C_LABEL: 109 return "C_LABEL (Label)"; 110 case XCOFF::StorageClass::C_ULABEL: 111 return "C_ULABEL (Undefined label)"; 112 case XCOFF::StorageClass::C_MOS: 113 return "C_MOS (Member of structure)"; 114 case XCOFF::StorageClass::C_ARG: 115 return "C_ARG (Function argument)"; 116 case XCOFF::StorageClass::C_STRTAG: 117 return "C_STRTAG (Structure tag)"; 118 case XCOFF::StorageClass::C_MOU: 119 return "C_MOU (Member of union)"; 120 case XCOFF::StorageClass::C_UNTAG: 121 return "C_UNTAG (Union tag)"; 122 case XCOFF::StorageClass::C_TPDEF: 123 return "C_TPDEF (Type definition)"; 124 case XCOFF::StorageClass::C_USTATIC: 125 return "C_USTATIC (Undefined static)"; 126 case XCOFF::StorageClass::C_ENTAG: 127 return "C_ENTAG (Enumeration tag)"; 128 case XCOFF::StorageClass::C_MOE: 129 return "C_MOE (Member of enumeration)"; 130 case XCOFF::StorageClass::C_REGPARM: 131 return "C_REGPARM (Register parameter)"; 132 case XCOFF::StorageClass::C_FIELD: 133 return "C_FIELD (Bit field)"; 134 case XCOFF::StorageClass::C_EOS: 135 return "C_EOS (End of structure)"; 136 case XCOFF::StorageClass::C_LINE: 137 return "C_LINE"; 138 case XCOFF::StorageClass::C_ALIAS: 139 return "C_ALIAS (Duplicate tag)"; 140 case XCOFF::StorageClass::C_HIDDEN: 141 return "C_HIDDEN (Special storage class for external)"; 142 case XCOFF::StorageClass::C_EFCN: 143 return "C_EFCN (Physical end of function)"; 144 case XCOFF::StorageClass::C_TCSYM: 145 return "C_TCSYM (Reserved)"; 146 } 147 llvm_unreachable("Unknown XCOFF::StorageClass enum"); 148 } 149 #endif 150 151 Error XCOFFLinkGraphBuilder::processSections() { 152 LLVM_DEBUG(dbgs() << " Creating graph sections...\n"); 153 154 UndefSection = &G->createSection("*UND*", orc::MemProt::None); 155 156 for (object::SectionRef Section : Obj.sections()) { 157 auto SectionName = Section.getName(); 158 if (!SectionName) 159 return SectionName.takeError(); 160 161 LLVM_DEBUG({ 162 dbgs() << " section = " << *SectionName 163 << ", idx = " << Section.getIndex() 164 << ", size = " << format_hex_no_prefix(Section.getSize(), 8) 165 << ", vma = " << format_hex(Section.getAddress(), 16) << "\n"; 166 }); 167 168 // We can skip debug (including dawrf) and pad sections 169 if (Section.isDebugSection() || *SectionName == "pad") 170 continue; 171 LLVM_DEBUG(dbgs() << " creating graph section\n"); 172 173 orc::MemProt Prot = orc::MemProt::Read; 174 if (Section.isText()) 175 Prot |= orc::MemProt::Exec; 176 if (Section.isData() || Section.isBSS()) 177 Prot |= orc::MemProt::Write; 178 179 jitlink::Section *GraphSec = &G->createSection(*SectionName, Prot); 180 // TODO: Check for no_alloc for certain sections 181 182 assert(!SectionTable.contains(Section.getIndex()) && 183 "Section with same index already exists"); 184 SectionTable[Section.getIndex()] = {GraphSec, Section}; 185 } 186 187 return Error::success(); 188 } 189 190 static std::optional<object::XCOFFSymbolRef> 191 getXCOFFSymbolContainingSymbolRef(const object::XCOFFObjectFile &Obj, 192 const object::SymbolRef &Sym) { 193 const object::XCOFFSymbolRef SymRef = 194 Obj.toSymbolRef(Sym.getRawDataRefImpl()); 195 if (!SymRef.isCsectSymbol()) 196 return std::nullopt; 197 198 Expected<object::XCOFFCsectAuxRef> CsectAuxEntOrErr = 199 SymRef.getXCOFFCsectAuxRef(); 200 if (!CsectAuxEntOrErr || !CsectAuxEntOrErr.get().isLabel()) 201 return std::nullopt; 202 uint32_t Idx = 203 static_cast<uint32_t>(CsectAuxEntOrErr.get().getSectionOrLength()); 204 object::DataRefImpl DRI; 205 DRI.p = Obj.getSymbolByIndex(Idx); 206 return object::XCOFFSymbolRef(DRI, &Obj); 207 } 208 209 #ifndef NDEBUG 210 static void printSymbolEntry(raw_ostream &OS, 211 const object::XCOFFObjectFile &Obj, 212 const object::XCOFFSymbolRef &Sym) { 213 OS << " " << format_hex(cantFail(Sym.getAddress()), 16); 214 OS << " " << left_justify(cantFail(Sym.getName()), 10); 215 if (Sym.isCsectSymbol()) { 216 auto CsectAuxEntry = cantFail(Sym.getXCOFFCsectAuxRef()); 217 if (!CsectAuxEntry.isLabel()) { 218 std::string MCStr = 219 "[" + 220 XCOFF::getMappingClassString(CsectAuxEntry.getStorageMappingClass()) 221 .str() + 222 "]"; 223 OS << left_justify(MCStr, 3); 224 } 225 } 226 OS << " " << format_hex(Sym.getSize(), 8); 227 OS << " " << Sym.getSectionNumber(); 228 OS << " " << getStorageClassString(Sym.getStorageClass()); 229 OS << " (idx: " << Obj.getSymbolIndex(Sym.getRawDataRefImpl().p) << ")"; 230 if (Sym.isCsectSymbol()) { 231 if (auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Sym)) { 232 OS << " (csect idx: " 233 << Obj.getSymbolIndex(ParentSym->getRawDataRefImpl().p) << ")"; 234 } 235 } 236 OS << "\n"; 237 } 238 #endif 239 240 Error XCOFFLinkGraphBuilder::processCsectsAndSymbols() { 241 LLVM_DEBUG(dbgs() << " Creating graph blocks and symbols...\n"); 242 243 for ([[maybe_unused]] auto [K, V] : SectionTable) { 244 LLVM_DEBUG(dbgs() << " section entry(idx: " << K 245 << " section: " << V.Section->getName() << ")\n"); 246 } 247 248 for (object::XCOFFSymbolRef Symbol : Obj.symbols()) { 249 LLVM_DEBUG({ printSymbolEntry(dbgs(), Obj, Symbol); }); 250 251 auto Flags = Symbol.getFlags(); 252 if (!Flags) 253 return Flags.takeError(); 254 255 bool External = *Flags & object::SymbolRef::SF_Undefined; 256 bool Weak = *Flags & object::SymbolRef::SF_Weak; 257 bool Global = *Flags & object::SymbolRef::SF_Global; 258 259 auto SymbolIndex = Obj.getSymbolIndex(Symbol.getEntryAddress()); 260 auto SymbolName = Symbol.getName(); 261 if (!SymbolName) 262 return SymbolName.takeError(); 263 264 if (External) { 265 LLVM_DEBUG(dbgs() << " created external symbol\n"); 266 SymbolIndexTable[SymbolIndex] = 267 &G->addExternalSymbol(*SymbolName, Symbol.getSize(), Weak); 268 continue; 269 } 270 271 if (!Symbol.isCsectSymbol()) { 272 LLVM_DEBUG(dbgs() << " skipped: not a csect symbol\n"); 273 continue; 274 } 275 276 auto ParentSym = getXCOFFSymbolContainingSymbolRef(Obj, Symbol); 277 object::XCOFFSymbolRef CsectSymbol = ParentSym ? *ParentSym : Symbol; 278 279 auto CsectSymbolIndex = Obj.getSymbolIndex(CsectSymbol.getEntryAddress()); 280 auto ParentSectionNumber = CsectSymbol.getSectionNumber(); 281 282 bool IsUndefinedSection = !SectionTable.contains(ParentSectionNumber); 283 Section *ParentSection = !IsUndefinedSection 284 ? SectionTable[ParentSectionNumber].Section 285 : UndefSection; 286 Block *B = nullptr; 287 288 // TODO: Clean up the logic for handling undefined symbols 289 if (!CsectTable.contains(CsectSymbolIndex) && !IsUndefinedSection) { 290 object::SectionRef &SectionRef = 291 SectionTable[ParentSectionNumber].SectionData; 292 auto Data = SectionRef.getContents(); 293 if (!Data) 294 return Data.takeError(); 295 auto CsectSymbolAddr = CsectSymbol.getAddress(); 296 if (!CsectSymbolAddr) 297 return CsectSymbolAddr.takeError(); 298 299 ArrayRef<char> SectionBuffer{*Data}; 300 auto Offset = *CsectSymbolAddr - SectionRef.getAddress(); 301 302 LLVM_DEBUG(dbgs() << " symbol entry: offset = " << Offset 303 << ", size = " << CsectSymbol.getSize() 304 << ", storage class = " 305 << getStorageClassString(CsectSymbol.getStorageClass()) 306 << "\n"); 307 308 B = &G->createContentBlock( 309 *ParentSection, SectionBuffer.slice(Offset, CsectSymbol.getSize()), 310 orc::ExecutorAddr(*CsectSymbolAddr), CsectSymbol.getAlignment(), 0); 311 312 CsectTable[CsectSymbolIndex] = B; 313 } else { 314 B = CsectTable[CsectSymbolIndex]; 315 } 316 317 Scope S{Scope::Local}; 318 if (Symbol.getSymbolType() & XCOFF::SYM_V_HIDDEN || 319 Symbol.getSymbolType() & XCOFF::SYM_V_INTERNAL) 320 S = Scope::Hidden; 321 else if (Global) 322 S = Scope::Default; 323 // TODO: map all symbols for c++ static initialization to SideEffectOnly 324 325 Linkage L = Weak ? Linkage::Weak : Linkage::Strong; 326 auto SymbolAddr = Symbol.getAddress(); 327 if (!SymbolAddr) 328 return SymbolAddr.takeError(); 329 auto IsCallableOrErr = Symbol.isFunction(); 330 if (!IsCallableOrErr) 331 return IsCallableOrErr.takeError(); 332 333 auto BlockOffset = *SymbolAddr - B->getAddress().getValue(); 334 335 LLVM_DEBUG(dbgs() << " creating with linkage = " << getLinkageName(L) 336 << ", scope = " << getScopeName(S) << ", B = " 337 << format_hex(B->getAddress().getValue(), 16) << "\n"); 338 339 SymbolIndexTable[SymbolIndex] = 340 &G->addDefinedSymbol(*B, BlockOffset, *SymbolName, Symbol.getSize(), L, 341 S, *IsCallableOrErr, true); 342 } 343 344 return Error::success(); 345 } 346 347 Error XCOFFLinkGraphBuilder::processRelocations() { 348 LLVM_DEBUG(dbgs() << " Creating relocations...\n"); 349 350 for (object::SectionRef Section : Obj.sections()) { 351 auto SectionName = Section.getName(); 352 if (!SectionName) 353 return SectionName.takeError(); 354 355 LLVM_DEBUG(dbgs() << " Relocations for section " << *SectionName 356 << ":\n"); 357 358 for (object::RelocationRef Relocation : Section.relocations()) { 359 SmallString<16> RelocName; 360 Relocation.getTypeName(RelocName); 361 object::SymbolRef Symbol = *Relocation.getSymbol(); 362 363 auto TargetSymbol = Symbol.getName(); 364 if (!TargetSymbol) 365 return TargetSymbol.takeError(); 366 367 auto SymbolIndex = Obj.getSymbolIndex(Symbol.getRawDataRefImpl().p); 368 369 LLVM_DEBUG(dbgs() << " " << format_hex(Relocation.getOffset(), 16) 370 << " (idx: " << SymbolIndex << ")" 371 << " " << RelocName << " " << *TargetSymbol << "\n";); 372 373 assert(SymbolIndexTable.contains(SymbolIndex) && 374 "Relocation needs a record in the symbol table"); 375 auto *S = SymbolIndexTable[SymbolIndex]; 376 auto It = find_if(G->blocks(), 377 [Target = orc::ExecutorAddr(Section.getAddress() + 378 Relocation.getOffset())]( 379 const Block *B) -> bool { 380 return B->getRange().contains(Target); 381 }); 382 assert(It != G->blocks().end() && 383 "Cannot find the target relocation block"); 384 Block *B = *It; 385 386 auto TargetBlockOffset = Section.getAddress() + Relocation.getOffset() - 387 B->getAddress().getValue(); 388 switch (Relocation.getType()) { 389 case XCOFF::R_POS: 390 B->addEdge(ppc64::EdgeKind_ppc64::Pointer64, TargetBlockOffset, *S, 0); 391 break; 392 default: 393 SmallString<16> RelocType; 394 Relocation.getTypeName(RelocType); 395 return make_error<StringError>( 396 "Unsupported Relocation Type: " + RelocType, std::error_code()); 397 } 398 } 399 } 400 401 return Error::success(); 402 } 403 404 Expected<std::unique_ptr<LinkGraph>> XCOFFLinkGraphBuilder::buildGraph() { 405 LLVM_DEBUG(dbgs() << "Building XCOFFLinkGraph...\n"); 406 407 // FIXME: Check to make sure the object is relocatable 408 409 if (auto Err = processSections()) 410 return Err; 411 if (auto Err = processCsectsAndSymbols()) 412 return Err; 413 if (auto Err = processRelocations()) 414 return Err; 415 416 return std::move(G); 417 } 418 419 } // namespace jitlink 420 } // namespace llvm 421