1 //===--- XCOFFObjectFile.cpp - XCOFF object file implementation -----------===// 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 // This file defines the XCOFFObjectFile class. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Object/XCOFFObjectFile.h" 14 #include "llvm/MC/SubtargetFeature.h" 15 #include <cstddef> 16 #include <cstring> 17 18 namespace llvm { 19 namespace object { 20 21 static const uint8_t FunctionSym = 0x20; 22 static const uint8_t SymTypeMask = 0x07; 23 static const uint16_t NoRelMask = 0x0001; 24 25 // Checks that [Ptr, Ptr + Size) bytes fall inside the memory buffer 26 // 'M'. Returns a pointer to the underlying object on success. 27 template <typename T> 28 static Expected<const T *> getObject(MemoryBufferRef M, const void *Ptr, 29 const uint64_t Size = sizeof(T)) { 30 uintptr_t Addr = uintptr_t(Ptr); 31 if (Error E = Binary::checkOffset(M, Addr, Size)) 32 return std::move(E); 33 return reinterpret_cast<const T *>(Addr); 34 } 35 36 static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) { 37 return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) + 38 Offset); 39 } 40 41 template <typename T> static const T *viewAs(uintptr_t in) { 42 return reinterpret_cast<const T *>(in); 43 } 44 45 static StringRef generateXCOFFFixedNameStringRef(const char *Name) { 46 auto NulCharPtr = 47 static_cast<const char *>(memchr(Name, '\0', XCOFF::NameSize)); 48 return NulCharPtr ? StringRef(Name, NulCharPtr - Name) 49 : StringRef(Name, XCOFF::NameSize); 50 } 51 52 template <typename T> StringRef XCOFFSectionHeader<T>::getName() const { 53 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); 54 return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name); 55 } 56 57 template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const { 58 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); 59 return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask; 60 } 61 62 template <typename T> 63 bool XCOFFSectionHeader<T>::isReservedSectionType() const { 64 return getSectionType() & SectionFlagsReservedMask; 65 } 66 67 bool XCOFFRelocation32::isRelocationSigned() const { 68 return Info & XR_SIGN_INDICATOR_MASK; 69 } 70 71 bool XCOFFRelocation32::isFixupIndicated() const { 72 return Info & XR_FIXUP_INDICATOR_MASK; 73 } 74 75 uint8_t XCOFFRelocation32::getRelocatedLength() const { 76 // The relocation encodes the bit length being relocated minus 1. Add back 77 // the 1 to get the actual length being relocated. 78 return (Info & XR_BIASED_LENGTH_MASK) + 1; 79 } 80 81 void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr, 82 uintptr_t TableAddress) const { 83 if (Addr < TableAddress) 84 report_fatal_error("Section header outside of section header table."); 85 86 uintptr_t Offset = Addr - TableAddress; 87 if (Offset >= getSectionHeaderSize() * getNumberOfSections()) 88 report_fatal_error("Section header outside of section header table."); 89 90 if (Offset % getSectionHeaderSize() != 0) 91 report_fatal_error( 92 "Section header pointer does not point to a valid section header."); 93 } 94 95 const XCOFFSectionHeader32 * 96 XCOFFObjectFile::toSection32(DataRefImpl Ref) const { 97 assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 98 #ifndef NDEBUG 99 checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); 100 #endif 101 return viewAs<XCOFFSectionHeader32>(Ref.p); 102 } 103 104 const XCOFFSectionHeader64 * 105 XCOFFObjectFile::toSection64(DataRefImpl Ref) const { 106 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 107 #ifndef NDEBUG 108 checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); 109 #endif 110 return viewAs<XCOFFSectionHeader64>(Ref.p); 111 } 112 113 const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const { 114 assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 115 assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!"); 116 #ifndef NDEBUG 117 checkSymbolEntryPointer(Ref.p); 118 #endif 119 auto SymEntPtr = viewAs<XCOFFSymbolEntry>(Ref.p); 120 return SymEntPtr; 121 } 122 123 const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const { 124 assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 125 return static_cast<const XCOFFFileHeader32 *>(FileHeader); 126 } 127 128 const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const { 129 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 130 return static_cast<const XCOFFFileHeader64 *>(FileHeader); 131 } 132 133 const XCOFFSectionHeader32 * 134 XCOFFObjectFile::sectionHeaderTable32() const { 135 assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 136 return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable); 137 } 138 139 const XCOFFSectionHeader64 * 140 XCOFFObjectFile::sectionHeaderTable64() const { 141 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 142 return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable); 143 } 144 145 void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { 146 const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); 147 SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1; 148 #ifndef NDEBUG 149 // This function is used by basic_symbol_iterator, which allows to 150 // point to the end-of-symbol-table address. 151 if (reinterpret_cast<uintptr_t>(SymEntPtr) != getEndOfSymbolTableAddress()) 152 checkSymbolEntryPointer(reinterpret_cast<uintptr_t>(SymEntPtr)); 153 #endif 154 Symb.p = reinterpret_cast<uintptr_t>(SymEntPtr); 155 } 156 157 Expected<StringRef> 158 XCOFFObjectFile::getStringTableEntry(uint32_t Offset) const { 159 // The byte offset is relative to the start of the string table. 160 // A byte offset value of 0 is a null or zero-length symbol 161 // name. A byte offset in the range 1 to 3 (inclusive) points into the length 162 // field; as a soft-error recovery mechanism, we treat such cases as having an 163 // offset of 0. 164 if (Offset < 4) 165 return StringRef(nullptr, 0); 166 167 if (StringTable.Data != nullptr && StringTable.Size > Offset) 168 return (StringTable.Data + Offset); 169 170 return make_error<GenericBinaryError>("Bad offset for string table entry", 171 object_error::parse_failed); 172 } 173 174 Expected<StringRef> 175 XCOFFObjectFile::getCFileName(const XCOFFFileAuxEnt *CFileEntPtr) const { 176 if (CFileEntPtr->NameInStrTbl.Magic != 177 XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) 178 return generateXCOFFFixedNameStringRef(CFileEntPtr->Name); 179 return getStringTableEntry(CFileEntPtr->NameInStrTbl.Offset); 180 } 181 182 Expected<StringRef> XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { 183 const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); 184 185 // A storage class value with the high-order bit on indicates that the name is 186 // a symbolic debugger stabstring. 187 if (SymEntPtr->StorageClass & 0x80) 188 return StringRef("Unimplemented Debug Name"); 189 190 if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) 191 return generateXCOFFFixedNameStringRef(SymEntPtr->SymbolName); 192 193 return getStringTableEntry(SymEntPtr->NameInStrTbl.Offset); 194 } 195 196 Expected<uint64_t> XCOFFObjectFile::getSymbolAddress(DataRefImpl Symb) const { 197 assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 198 return toSymbolEntry(Symb)->Value; 199 } 200 201 uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { 202 assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 203 return toSymbolEntry(Symb)->Value; 204 } 205 206 uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { 207 uint64_t Result = 0; 208 llvm_unreachable("Not yet implemented!"); 209 return Result; 210 } 211 212 Expected<SymbolRef::Type> 213 XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const { 214 llvm_unreachable("Not yet implemented!"); 215 return SymbolRef::ST_Other; 216 } 217 218 Expected<section_iterator> 219 XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { 220 const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); 221 int16_t SectNum = SymEntPtr->SectionNumber; 222 223 if (isReservedSectionNumber(SectNum)) 224 return section_end(); 225 226 Expected<DataRefImpl> ExpSec = getSectionByNum(SectNum); 227 if (!ExpSec) 228 return ExpSec.takeError(); 229 230 return section_iterator(SectionRef(ExpSec.get(), this)); 231 } 232 233 void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { 234 const char *Ptr = reinterpret_cast<const char *>(Sec.p); 235 Sec.p = reinterpret_cast<uintptr_t>(Ptr + getSectionHeaderSize()); 236 } 237 238 Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { 239 return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec)); 240 } 241 242 uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { 243 // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t 244 // with MSVC. 245 if (is64Bit()) 246 return toSection64(Sec)->VirtualAddress; 247 248 return toSection32(Sec)->VirtualAddress; 249 } 250 251 uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { 252 // Section numbers in XCOFF are numbered beginning at 1. A section number of 253 // zero is used to indicate that a symbol is being imported or is undefined. 254 if (is64Bit()) 255 return toSection64(Sec) - sectionHeaderTable64() + 1; 256 else 257 return toSection32(Sec) - sectionHeaderTable32() + 1; 258 } 259 260 uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const { 261 // Avoid ternary due to failure to convert the ubig32_t value to a unit64_t 262 // with MSVC. 263 if (is64Bit()) 264 return toSection64(Sec)->SectionSize; 265 266 return toSection32(Sec)->SectionSize; 267 } 268 269 Expected<ArrayRef<uint8_t>> 270 XCOFFObjectFile::getSectionContents(DataRefImpl Sec) const { 271 if (isSectionVirtual(Sec)) 272 return ArrayRef<uint8_t>(); 273 274 uint64_t OffsetToRaw; 275 if (is64Bit()) 276 OffsetToRaw = toSection64(Sec)->FileOffsetToRawData; 277 else 278 OffsetToRaw = toSection32(Sec)->FileOffsetToRawData; 279 280 const uint8_t * ContentStart = base() + OffsetToRaw; 281 uint64_t SectionSize = getSectionSize(Sec); 282 if (checkOffset(Data, uintptr_t(ContentStart), SectionSize)) 283 return make_error<BinaryError>(); 284 285 return makeArrayRef(ContentStart,SectionSize); 286 } 287 288 uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { 289 uint64_t Result = 0; 290 llvm_unreachable("Not yet implemented!"); 291 return Result; 292 } 293 294 bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { 295 bool Result = false; 296 llvm_unreachable("Not yet implemented!"); 297 return Result; 298 } 299 300 bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { 301 return getSectionFlags(Sec) & XCOFF::STYP_TEXT; 302 } 303 304 bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { 305 uint32_t Flags = getSectionFlags(Sec); 306 return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); 307 } 308 309 bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { 310 uint32_t Flags = getSectionFlags(Sec); 311 return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); 312 } 313 314 bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const { 315 return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0 316 : toSection32(Sec)->FileOffsetToRawData == 0; 317 } 318 319 relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { 320 if (is64Bit()) 321 report_fatal_error("64-bit support not implemented yet"); 322 const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); 323 auto RelocationsOrErr = relocations(*SectionEntPtr); 324 if (Error E = RelocationsOrErr.takeError()) 325 return relocation_iterator(RelocationRef()); 326 DataRefImpl Ret; 327 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().begin()); 328 return relocation_iterator(RelocationRef(Ret, this)); 329 } 330 331 relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const { 332 if (is64Bit()) 333 report_fatal_error("64-bit support not implemented yet"); 334 const XCOFFSectionHeader32 *SectionEntPtr = toSection32(Sec); 335 auto RelocationsOrErr = relocations(*SectionEntPtr); 336 if (Error E = RelocationsOrErr.takeError()) 337 return relocation_iterator(RelocationRef()); 338 DataRefImpl Ret; 339 Ret.p = reinterpret_cast<uintptr_t>(&*RelocationsOrErr.get().end()); 340 return relocation_iterator(RelocationRef(Ret, this)); 341 } 342 343 void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { 344 Rel.p = reinterpret_cast<uintptr_t>(viewAs<XCOFFRelocation32>(Rel.p) + 1); 345 } 346 347 uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { 348 if (is64Bit()) 349 report_fatal_error("64-bit support not implemented yet"); 350 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); 351 const XCOFFSectionHeader32 *Sec32 = sectionHeaderTable32(); 352 const uint32_t RelocAddress = Reloc->VirtualAddress; 353 const uint16_t NumberOfSections = getNumberOfSections(); 354 for (uint16_t i = 0; i < NumberOfSections; ++i) { 355 // Find which section this relocation is belonging to, and get the 356 // relocation offset relative to the start of the section. 357 if (Sec32->VirtualAddress <= RelocAddress && 358 RelocAddress < Sec32->VirtualAddress + Sec32->SectionSize) { 359 return RelocAddress - Sec32->VirtualAddress; 360 } 361 ++Sec32; 362 } 363 return InvalidRelocOffset; 364 } 365 366 symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { 367 if (is64Bit()) 368 report_fatal_error("64-bit support not implemented yet"); 369 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); 370 const uint32_t Index = Reloc->SymbolIndex; 371 372 if (Index >= getLogicalNumberOfSymbolTableEntries32()) 373 return symbol_end(); 374 375 DataRefImpl SymDRI; 376 SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index); 377 return symbol_iterator(SymbolRef(SymDRI, this)); 378 } 379 380 uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const { 381 if (is64Bit()) 382 report_fatal_error("64-bit support not implemented yet"); 383 return viewAs<XCOFFRelocation32>(Rel.p)->Type; 384 } 385 386 void XCOFFObjectFile::getRelocationTypeName( 387 DataRefImpl Rel, SmallVectorImpl<char> &Result) const { 388 if (is64Bit()) 389 report_fatal_error("64-bit support not implemented yet"); 390 const XCOFFRelocation32 *Reloc = viewAs<XCOFFRelocation32>(Rel.p); 391 StringRef Res = XCOFF::getRelocationTypeString(Reloc->Type); 392 Result.append(Res.begin(), Res.end()); 393 } 394 395 Expected<uint32_t> XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { 396 uint32_t Result = 0; 397 llvm_unreachable("Not yet implemented!"); 398 return Result; 399 } 400 401 basic_symbol_iterator XCOFFObjectFile::symbol_begin() const { 402 if (is64Bit()) 403 report_fatal_error("64-bit support not implemented yet"); 404 DataRefImpl SymDRI; 405 SymDRI.p = reinterpret_cast<uintptr_t>(SymbolTblPtr); 406 return basic_symbol_iterator(SymbolRef(SymDRI, this)); 407 } 408 409 basic_symbol_iterator XCOFFObjectFile::symbol_end() const { 410 if (is64Bit()) 411 report_fatal_error("64-bit support not implemented yet"); 412 DataRefImpl SymDRI; 413 SymDRI.p = reinterpret_cast<uintptr_t>( 414 SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32()); 415 return basic_symbol_iterator(SymbolRef(SymDRI, this)); 416 } 417 418 section_iterator XCOFFObjectFile::section_begin() const { 419 DataRefImpl DRI; 420 DRI.p = getSectionHeaderTableAddress(); 421 return section_iterator(SectionRef(DRI, this)); 422 } 423 424 section_iterator XCOFFObjectFile::section_end() const { 425 DataRefImpl DRI; 426 DRI.p = getWithOffset(getSectionHeaderTableAddress(), 427 getNumberOfSections() * getSectionHeaderSize()); 428 return section_iterator(SectionRef(DRI, this)); 429 } 430 431 uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } 432 433 StringRef XCOFFObjectFile::getFileFormatName() const { 434 return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000"; 435 } 436 437 Triple::ArchType XCOFFObjectFile::getArch() const { 438 return is64Bit() ? Triple::ppc64 : Triple::ppc; 439 } 440 441 SubtargetFeatures XCOFFObjectFile::getFeatures() const { 442 return SubtargetFeatures(); 443 } 444 445 bool XCOFFObjectFile::isRelocatableObject() const { 446 if (is64Bit()) 447 report_fatal_error("64-bit support not implemented yet"); 448 return !(fileHeader32()->Flags & NoRelMask); 449 } 450 451 Expected<uint64_t> XCOFFObjectFile::getStartAddress() const { 452 // TODO FIXME Should get from auxiliary_header->o_entry when support for the 453 // auxiliary_header is added. 454 return 0; 455 } 456 457 size_t XCOFFObjectFile::getFileHeaderSize() const { 458 return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32); 459 } 460 461 size_t XCOFFObjectFile::getSectionHeaderSize() const { 462 return is64Bit() ? sizeof(XCOFFSectionHeader64) : 463 sizeof(XCOFFSectionHeader32); 464 } 465 466 bool XCOFFObjectFile::is64Bit() const { 467 return Binary::ID_XCOFF64 == getType(); 468 } 469 470 uint16_t XCOFFObjectFile::getMagic() const { 471 return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; 472 } 473 474 Expected<DataRefImpl> XCOFFObjectFile::getSectionByNum(int16_t Num) const { 475 if (Num <= 0 || Num > getNumberOfSections()) 476 return errorCodeToError(object_error::invalid_section_index); 477 478 DataRefImpl DRI; 479 DRI.p = getWithOffset(getSectionHeaderTableAddress(), 480 getSectionHeaderSize() * (Num - 1)); 481 return DRI; 482 } 483 484 Expected<StringRef> 485 XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const { 486 assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 487 int16_t SectionNum = SymEntPtr->SectionNumber; 488 489 switch (SectionNum) { 490 case XCOFF::N_DEBUG: 491 return "N_DEBUG"; 492 case XCOFF::N_ABS: 493 return "N_ABS"; 494 case XCOFF::N_UNDEF: 495 return "N_UNDEF"; 496 default: 497 Expected<DataRefImpl> SecRef = getSectionByNum(SectionNum); 498 if (SecRef) 499 return generateXCOFFFixedNameStringRef( 500 getSectionNameInternal(SecRef.get())); 501 return SecRef.takeError(); 502 } 503 } 504 505 bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) { 506 return (SectionNumber <= 0 && SectionNumber >= -2); 507 } 508 509 uint16_t XCOFFObjectFile::getNumberOfSections() const { 510 return is64Bit() ? fileHeader64()->NumberOfSections 511 : fileHeader32()->NumberOfSections; 512 } 513 514 int32_t XCOFFObjectFile::getTimeStamp() const { 515 return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp; 516 } 517 518 uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { 519 return is64Bit() ? fileHeader64()->AuxHeaderSize 520 : fileHeader32()->AuxHeaderSize; 521 } 522 523 uint32_t XCOFFObjectFile::getSymbolTableOffset32() const { 524 return fileHeader32()->SymbolTableOffset; 525 } 526 527 int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const { 528 // As far as symbol table size is concerned, if this field is negative it is 529 // to be treated as a 0. However since this field is also used for printing we 530 // don't want to truncate any negative values. 531 return fileHeader32()->NumberOfSymTableEntries; 532 } 533 534 uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const { 535 return (fileHeader32()->NumberOfSymTableEntries >= 0 536 ? fileHeader32()->NumberOfSymTableEntries 537 : 0); 538 } 539 540 uint64_t XCOFFObjectFile::getSymbolTableOffset64() const { 541 return fileHeader64()->SymbolTableOffset; 542 } 543 544 uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { 545 return fileHeader64()->NumberOfSymTableEntries; 546 } 547 548 uintptr_t XCOFFObjectFile::getEndOfSymbolTableAddress() const { 549 uint32_t NumberOfSymTableEntries = 550 is64Bit() ? getNumberOfSymbolTableEntries64() 551 : getLogicalNumberOfSymbolTableEntries32(); 552 return getWithOffset(reinterpret_cast<uintptr_t>(SymbolTblPtr), 553 XCOFF::SymbolTableEntrySize * NumberOfSymTableEntries); 554 } 555 556 void XCOFFObjectFile::checkSymbolEntryPointer(uintptr_t SymbolEntPtr) const { 557 if (SymbolEntPtr < reinterpret_cast<uintptr_t>(SymbolTblPtr)) 558 report_fatal_error("Symbol table entry is outside of symbol table."); 559 560 if (SymbolEntPtr >= getEndOfSymbolTableAddress()) 561 report_fatal_error("Symbol table entry is outside of symbol table."); 562 563 ptrdiff_t Offset = reinterpret_cast<const char *>(SymbolEntPtr) - 564 reinterpret_cast<const char *>(SymbolTblPtr); 565 566 if (Offset % XCOFF::SymbolTableEntrySize != 0) 567 report_fatal_error( 568 "Symbol table entry position is not valid inside of symbol table."); 569 } 570 571 uint32_t XCOFFObjectFile::getSymbolIndex(uintptr_t SymbolEntPtr) const { 572 return (reinterpret_cast<const char *>(SymbolEntPtr) - 573 reinterpret_cast<const char *>(SymbolTblPtr)) / 574 XCOFF::SymbolTableEntrySize; 575 } 576 577 Expected<StringRef> 578 XCOFFObjectFile::getSymbolNameByIndex(uint32_t Index) const { 579 if (is64Bit()) 580 report_fatal_error("64-bit symbol table support not implemented yet."); 581 582 if (Index >= getLogicalNumberOfSymbolTableEntries32()) 583 return errorCodeToError(object_error::invalid_symbol_index); 584 585 DataRefImpl SymDRI; 586 SymDRI.p = reinterpret_cast<uintptr_t>(getPointerToSymbolTable() + Index); 587 return getSymbolName(SymDRI); 588 } 589 590 uint16_t XCOFFObjectFile::getFlags() const { 591 return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; 592 } 593 594 const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const { 595 return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name; 596 } 597 598 uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const { 599 return reinterpret_cast<uintptr_t>(SectionHeaderTable); 600 } 601 602 int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const { 603 return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags; 604 } 605 606 XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object) 607 : ObjectFile(Type, Object) { 608 assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64); 609 } 610 611 ArrayRef<XCOFFSectionHeader64> XCOFFObjectFile::sections64() const { 612 assert(is64Bit() && "64-bit interface called for non 64-bit file."); 613 const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64(); 614 return ArrayRef<XCOFFSectionHeader64>(TablePtr, 615 TablePtr + getNumberOfSections()); 616 } 617 618 ArrayRef<XCOFFSectionHeader32> XCOFFObjectFile::sections32() const { 619 assert(!is64Bit() && "32-bit interface called for non 32-bit file."); 620 const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32(); 621 return ArrayRef<XCOFFSectionHeader32>(TablePtr, 622 TablePtr + getNumberOfSections()); 623 } 624 625 // In an XCOFF32 file, when the field value is 65535, then an STYP_OVRFLO 626 // section header contains the actual count of relocation entries in the s_paddr 627 // field. STYP_OVRFLO headers contain the section index of their corresponding 628 // sections as their raw "NumberOfRelocations" field value. 629 Expected<uint32_t> XCOFFObjectFile::getLogicalNumberOfRelocationEntries( 630 const XCOFFSectionHeader32 &Sec) const { 631 632 uint16_t SectionIndex = &Sec - sectionHeaderTable32() + 1; 633 634 if (Sec.NumberOfRelocations < XCOFF::RelocOverflow) 635 return Sec.NumberOfRelocations; 636 for (const auto &Sec : sections32()) { 637 if (Sec.Flags == XCOFF::STYP_OVRFLO && 638 Sec.NumberOfRelocations == SectionIndex) 639 return Sec.PhysicalAddress; 640 } 641 return errorCodeToError(object_error::parse_failed); 642 } 643 644 Expected<ArrayRef<XCOFFRelocation32>> 645 XCOFFObjectFile::relocations(const XCOFFSectionHeader32 &Sec) const { 646 uintptr_t RelocAddr = getWithOffset(reinterpret_cast<uintptr_t>(FileHeader), 647 Sec.FileOffsetToRelocationInfo); 648 auto NumRelocEntriesOrErr = getLogicalNumberOfRelocationEntries(Sec); 649 if (Error E = NumRelocEntriesOrErr.takeError()) 650 return std::move(E); 651 652 uint32_t NumRelocEntries = NumRelocEntriesOrErr.get(); 653 654 assert(sizeof(XCOFFRelocation32) == XCOFF::RelocationSerializationSize32); 655 auto RelocationOrErr = 656 getObject<XCOFFRelocation32>(Data, reinterpret_cast<void *>(RelocAddr), 657 NumRelocEntries * sizeof(XCOFFRelocation32)); 658 if (Error E = RelocationOrErr.takeError()) 659 return std::move(E); 660 661 const XCOFFRelocation32 *StartReloc = RelocationOrErr.get(); 662 663 return ArrayRef<XCOFFRelocation32>(StartReloc, StartReloc + NumRelocEntries); 664 } 665 666 Expected<XCOFFStringTable> 667 XCOFFObjectFile::parseStringTable(const XCOFFObjectFile *Obj, uint64_t Offset) { 668 // If there is a string table, then the buffer must contain at least 4 bytes 669 // for the string table's size. Not having a string table is not an error. 670 if (Error E = Binary::checkOffset( 671 Obj->Data, reinterpret_cast<uintptr_t>(Obj->base() + Offset), 4)) { 672 consumeError(std::move(E)); 673 return XCOFFStringTable{0, nullptr}; 674 } 675 676 // Read the size out of the buffer. 677 uint32_t Size = support::endian::read32be(Obj->base() + Offset); 678 679 // If the size is less then 4, then the string table is just a size and no 680 // string data. 681 if (Size <= 4) 682 return XCOFFStringTable{4, nullptr}; 683 684 auto StringTableOrErr = 685 getObject<char>(Obj->Data, Obj->base() + Offset, Size); 686 if (Error E = StringTableOrErr.takeError()) 687 return std::move(E); 688 689 const char *StringTablePtr = StringTableOrErr.get(); 690 if (StringTablePtr[Size - 1] != '\0') 691 return errorCodeToError(object_error::string_table_non_null_end); 692 693 return XCOFFStringTable{Size, StringTablePtr}; 694 } 695 696 Expected<std::unique_ptr<XCOFFObjectFile>> 697 XCOFFObjectFile::create(unsigned Type, MemoryBufferRef MBR) { 698 // Can't use std::make_unique because of the private constructor. 699 std::unique_ptr<XCOFFObjectFile> Obj; 700 Obj.reset(new XCOFFObjectFile(Type, MBR)); 701 702 uint64_t CurOffset = 0; 703 const auto *Base = Obj->base(); 704 MemoryBufferRef Data = Obj->Data; 705 706 // Parse file header. 707 auto FileHeaderOrErr = 708 getObject<void>(Data, Base + CurOffset, Obj->getFileHeaderSize()); 709 if (Error E = FileHeaderOrErr.takeError()) 710 return std::move(E); 711 Obj->FileHeader = FileHeaderOrErr.get(); 712 713 CurOffset += Obj->getFileHeaderSize(); 714 // TODO FIXME we don't have support for an optional header yet, so just skip 715 // past it. 716 CurOffset += Obj->getOptionalHeaderSize(); 717 718 // Parse the section header table if it is present. 719 if (Obj->getNumberOfSections()) { 720 auto SecHeadersOrErr = getObject<void>(Data, Base + CurOffset, 721 Obj->getNumberOfSections() * 722 Obj->getSectionHeaderSize()); 723 if (Error E = SecHeadersOrErr.takeError()) 724 return std::move(E); 725 Obj->SectionHeaderTable = SecHeadersOrErr.get(); 726 } 727 728 // 64-bit object supports only file header and section headers for now. 729 if (Obj->is64Bit()) 730 return std::move(Obj); 731 732 // If there is no symbol table we are done parsing the memory buffer. 733 if (Obj->getLogicalNumberOfSymbolTableEntries32() == 0) 734 return std::move(Obj); 735 736 // Parse symbol table. 737 CurOffset = Obj->fileHeader32()->SymbolTableOffset; 738 uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) * 739 Obj->getLogicalNumberOfSymbolTableEntries32(); 740 auto SymTableOrErr = 741 getObject<XCOFFSymbolEntry>(Data, Base + CurOffset, SymbolTableSize); 742 if (Error E = SymTableOrErr.takeError()) 743 return std::move(E); 744 Obj->SymbolTblPtr = SymTableOrErr.get(); 745 CurOffset += SymbolTableSize; 746 747 // Parse String table. 748 Expected<XCOFFStringTable> StringTableOrErr = 749 parseStringTable(Obj.get(), CurOffset); 750 if (Error E = StringTableOrErr.takeError()) 751 return std::move(E); 752 Obj->StringTable = StringTableOrErr.get(); 753 754 return std::move(Obj); 755 } 756 757 Expected<std::unique_ptr<ObjectFile>> 758 ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef, 759 unsigned FileType) { 760 return XCOFFObjectFile::create(FileType, MemBufRef); 761 } 762 763 XCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const { 764 return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass; 765 } 766 767 uint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const { 768 return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries; 769 } 770 771 // TODO: The function needs to return an error if there is no csect auxiliary 772 // entry. 773 const XCOFFCsectAuxEnt32 *XCOFFSymbolRef::getXCOFFCsectAuxEnt32() const { 774 assert(!OwningObjectPtr->is64Bit() && 775 "32-bit interface called on 64-bit object file."); 776 assert(hasCsectAuxEnt() && "No Csect Auxiliary Entry is found."); 777 778 // In XCOFF32, the csect auxilliary entry is always the last auxiliary 779 // entry for the symbol. 780 uintptr_t AuxAddr = getWithOffset( 781 SymEntDataRef.p, XCOFF::SymbolTableEntrySize * getNumberOfAuxEntries()); 782 783 #ifndef NDEBUG 784 OwningObjectPtr->checkSymbolEntryPointer(AuxAddr); 785 #endif 786 787 return reinterpret_cast<const XCOFFCsectAuxEnt32 *>(AuxAddr); 788 } 789 790 uint16_t XCOFFSymbolRef::getType() const { 791 return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType; 792 } 793 794 int16_t XCOFFSymbolRef::getSectionNumber() const { 795 return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber; 796 } 797 798 // TODO: The function name needs to be changed to express the purpose of the 799 // function. 800 bool XCOFFSymbolRef::hasCsectAuxEnt() const { 801 XCOFF::StorageClass SC = getStorageClass(); 802 return (SC == XCOFF::C_EXT || SC == XCOFF::C_WEAKEXT || 803 SC == XCOFF::C_HIDEXT); 804 } 805 806 bool XCOFFSymbolRef::isFunction() const { 807 if (OwningObjectPtr->is64Bit()) 808 report_fatal_error("64-bit support is unimplemented yet."); 809 810 if (getType() & FunctionSym) 811 return true; 812 813 if (!hasCsectAuxEnt()) 814 return false; 815 816 const XCOFFCsectAuxEnt32 *CsectAuxEnt = getXCOFFCsectAuxEnt32(); 817 818 // A function definition should be a label definition. 819 if ((CsectAuxEnt->SymbolAlignmentAndType & SymTypeMask) != XCOFF::XTY_LD) 820 return false; 821 822 if (CsectAuxEnt->StorageMappingClass != XCOFF::XMC_PR) 823 return false; 824 825 int16_t SectNum = getSectionNumber(); 826 Expected<DataRefImpl> SI = OwningObjectPtr->getSectionByNum(SectNum); 827 if (!SI) 828 return false; 829 830 return (OwningObjectPtr->getSectionFlags(SI.get()) & XCOFF::STYP_TEXT); 831 } 832 833 // Explictly instantiate template classes. 834 template struct XCOFFSectionHeader<XCOFFSectionHeader32>; 835 template struct XCOFFSectionHeader<XCOFFSectionHeader64>; 836 837 } // namespace object 838 } // namespace llvm 839