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