XCOFFObjectFile.cpp revision 360784
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 17namespace llvm { 18namespace object { 19 20enum { 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. 24template <typename T> 25static 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 33static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) { 34 return reinterpret_cast<uintptr_t>(reinterpret_cast<const char *>(Base) + 35 Offset); 36} 37 38template <typename T> static const T *viewAs(uintptr_t in) { 39 return reinterpret_cast<const T *>(in); 40} 41 42static 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 49template <typename T> StringRef XCOFFSectionHeader<T>::getName() const { 50 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); 51 return generateXCOFFFixedNameStringRef(DerivedXCOFFSectionHeader.Name); 52} 53 54template <typename T> uint16_t XCOFFSectionHeader<T>::getSectionType() const { 55 const T &DerivedXCOFFSectionHeader = static_cast<const T &>(*this); 56 return DerivedXCOFFSectionHeader.Flags & SectionFlagsTypeMask; 57} 58 59template <typename T> 60bool XCOFFSectionHeader<T>::isReservedSectionType() const { 61 return getSectionType() & SectionFlagsReservedMask; 62} 63 64bool XCOFFRelocation32::isRelocationSigned() const { 65 return Info & XR_SIGN_INDICATOR_MASK; 66} 67 68bool XCOFFRelocation32::isFixupIndicated() const { 69 return Info & XR_FIXUP_INDICATOR_MASK; 70} 71 72uint8_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 78void 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 92const XCOFFSectionHeader32 * 93XCOFFObjectFile::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 101const XCOFFSectionHeader64 * 102XCOFFObjectFile::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 110const 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 120const 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 125const 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 130const XCOFFSectionHeader32 * 131XCOFFObjectFile::sectionHeaderTable32() const { 132 assert(!is64Bit() && "32-bit interface called on 64-bit object file."); 133 return static_cast<const XCOFFSectionHeader32 *>(SectionHeaderTable); 134} 135 136const XCOFFSectionHeader64 * 137XCOFFObjectFile::sectionHeaderTable64() const { 138 assert(is64Bit() && "64-bit interface called on a 32-bit object file."); 139 return static_cast<const XCOFFSectionHeader64 *>(SectionHeaderTable); 140} 141 142void 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 154Expected<StringRef> 155XCOFFObjectFile::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 171Expected<StringRef> 172XCOFFObjectFile::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 179Expected<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 193Expected<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 198uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { 199 assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); 200 return toSymbolEntry(Symb)->Value; 201} 202 203uint64_t XCOFFObjectFile::getCommonSymbolSizeImpl(DataRefImpl Symb) const { 204 uint64_t Result = 0; 205 llvm_unreachable("Not yet implemented!"); 206 return Result; 207} 208 209Expected<SymbolRef::Type> 210XCOFFObjectFile::getSymbolType(DataRefImpl Symb) const { 211 llvm_unreachable("Not yet implemented!"); 212 return SymbolRef::ST_Other; 213} 214 215Expected<section_iterator> 216XCOFFObjectFile::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 230void 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 235Expected<StringRef> XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { 236 return generateXCOFFFixedNameStringRef(getSectionNameInternal(Sec)); 237} 238 239uint64_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 248uint64_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 257uint64_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 266Expected<ArrayRef<uint8_t>> 267XCOFFObjectFile::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 285uint64_t XCOFFObjectFile::getSectionAlignment(DataRefImpl Sec) const { 286 uint64_t Result = 0; 287 llvm_unreachable("Not yet implemented!"); 288 return Result; 289} 290 291bool XCOFFObjectFile::isSectionCompressed(DataRefImpl Sec) const { 292 bool Result = false; 293 llvm_unreachable("Not yet implemented!"); 294 return Result; 295} 296 297bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { 298 return getSectionFlags(Sec) & XCOFF::STYP_TEXT; 299} 300 301bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { 302 uint32_t Flags = getSectionFlags(Sec); 303 return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); 304} 305 306bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { 307 uint32_t Flags = getSectionFlags(Sec); 308 return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); 309} 310 311bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const { 312 return is64Bit() ? toSection64(Sec)->FileOffsetToRawData == 0 313 : toSection32(Sec)->FileOffsetToRawData == 0; 314} 315 316relocation_iterator XCOFFObjectFile::section_rel_begin(DataRefImpl Sec) const { 317 llvm_unreachable("Not yet implemented!"); 318 return relocation_iterator(RelocationRef()); 319} 320 321relocation_iterator XCOFFObjectFile::section_rel_end(DataRefImpl Sec) const { 322 llvm_unreachable("Not yet implemented!"); 323 return relocation_iterator(RelocationRef()); 324} 325 326void XCOFFObjectFile::moveRelocationNext(DataRefImpl &Rel) const { 327 llvm_unreachable("Not yet implemented!"); 328 return; 329} 330 331uint64_t XCOFFObjectFile::getRelocationOffset(DataRefImpl Rel) const { 332 llvm_unreachable("Not yet implemented!"); 333 uint64_t Result = 0; 334 return Result; 335} 336 337symbol_iterator XCOFFObjectFile::getRelocationSymbol(DataRefImpl Rel) const { 338 llvm_unreachable("Not yet implemented!"); 339 return symbol_iterator(SymbolRef()); 340} 341 342uint64_t XCOFFObjectFile::getRelocationType(DataRefImpl Rel) const { 343 llvm_unreachable("Not yet implemented!"); 344 uint64_t Result = 0; 345 return Result; 346} 347 348void XCOFFObjectFile::getRelocationTypeName( 349 DataRefImpl Rel, SmallVectorImpl<char> &Result) const { 350 llvm_unreachable("Not yet implemented!"); 351 return; 352} 353 354uint32_t XCOFFObjectFile::getSymbolFlags(DataRefImpl Symb) const { 355 uint32_t Result = 0; 356 llvm_unreachable("Not yet implemented!"); 357 return Result; 358} 359 360basic_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 367basic_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 375section_iterator XCOFFObjectFile::section_begin() const { 376 DataRefImpl DRI; 377 DRI.p = getSectionHeaderTableAddress(); 378 return section_iterator(SectionRef(DRI, this)); 379} 380 381section_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 388uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } 389 390StringRef XCOFFObjectFile::getFileFormatName() const { 391 return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000"; 392} 393 394Triple::ArchType XCOFFObjectFile::getArch() const { 395 return is64Bit() ? Triple::ppc64 : Triple::ppc; 396} 397 398SubtargetFeatures XCOFFObjectFile::getFeatures() const { 399 return SubtargetFeatures(); 400} 401 402bool XCOFFObjectFile::isRelocatableObject() const { 403 bool Result = false; 404 llvm_unreachable("Not yet implemented!"); 405 return Result; 406} 407 408Expected<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 414size_t XCOFFObjectFile::getFileHeaderSize() const { 415 return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32); 416} 417 418size_t XCOFFObjectFile::getSectionHeaderSize() const { 419 return is64Bit() ? sizeof(XCOFFSectionHeader64) : 420 sizeof(XCOFFSectionHeader32); 421} 422 423bool XCOFFObjectFile::is64Bit() const { 424 return Binary::ID_XCOFF64 == getType(); 425} 426 427uint16_t XCOFFObjectFile::getMagic() const { 428 return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; 429} 430 431Expected<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 441Expected<StringRef> 442XCOFFObjectFile::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 462bool XCOFFObjectFile::isReservedSectionNumber(int16_t SectionNumber) { 463 return (SectionNumber <= 0 && SectionNumber >= -2); 464} 465 466uint16_t XCOFFObjectFile::getNumberOfSections() const { 467 return is64Bit() ? fileHeader64()->NumberOfSections 468 : fileHeader32()->NumberOfSections; 469} 470 471int32_t XCOFFObjectFile::getTimeStamp() const { 472 return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp; 473} 474 475uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { 476 return is64Bit() ? fileHeader64()->AuxHeaderSize 477 : fileHeader32()->AuxHeaderSize; 478} 479 480uint32_t XCOFFObjectFile::getSymbolTableOffset32() const { 481 return fileHeader32()->SymbolTableOffset; 482} 483 484int32_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 491uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const { 492 return (fileHeader32()->NumberOfSymTableEntries >= 0 493 ? fileHeader32()->NumberOfSymTableEntries 494 : 0); 495} 496 497uint64_t XCOFFObjectFile::getSymbolTableOffset64() const { 498 return fileHeader64()->SymbolTableOffset; 499} 500 501uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { 502 return fileHeader64()->NumberOfSymTableEntries; 503} 504 505uintptr_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 513void 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 528uint32_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 534Expected<StringRef> 535XCOFFObjectFile::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 547uint16_t XCOFFObjectFile::getFlags() const { 548 return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; 549} 550 551const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const { 552 return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name; 553} 554 555uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const { 556 return reinterpret_cast<uintptr_t>(SectionHeaderTable); 557} 558 559int32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const { 560 return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags; 561} 562 563XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object) 564 : ObjectFile(Type, Object) { 565 assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64); 566} 567 568ArrayRef<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 575ArrayRef<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. 586Expected<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 601Expected<ArrayRef<XCOFFRelocation32>> 602XCOFFObjectFile::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 622Expected<XCOFFStringTable> 623XCOFFObjectFile::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 650Expected<std::unique_ptr<XCOFFObjectFile>> 651XCOFFObjectFile::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 711Expected<std::unique_ptr<ObjectFile>> 712ObjectFile::createXCOFFObjectFile(MemoryBufferRef MemBufRef, 713 unsigned FileType) { 714 return XCOFFObjectFile::create(FileType, MemBufRef); 715} 716 717XCOFF::StorageClass XCOFFSymbolRef::getStorageClass() const { 718 return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->StorageClass; 719} 720 721uint8_t XCOFFSymbolRef::getNumberOfAuxEntries() const { 722 return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->NumberOfAuxEntries; 723} 724 725const 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 742uint16_t XCOFFSymbolRef::getType() const { 743 return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SymbolType; 744} 745 746int16_t XCOFFSymbolRef::getSectionNumber() const { 747 return OwningObjectPtr->toSymbolEntry(SymEntDataRef)->SectionNumber; 748} 749 750bool 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 756bool 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. 784template struct XCOFFSectionHeader<XCOFFSectionHeader32>; 785template struct XCOFFSectionHeader<XCOFFSectionHeader64>; 786 787} // namespace object 788} // namespace llvm 789