diff --git a/llvm/include/llvm/BinaryFormat/Magic.h b/llvm/include/llvm/BinaryFormat/Magic.h --- a/llvm/include/llvm/BinaryFormat/Magic.h +++ b/llvm/include/llvm/BinaryFormat/Magic.h @@ -46,6 +46,7 @@ pecoff_executable, ///< PECOFF executable file windows_resource, ///< Windows compiled resource file (.res) xcoff_object_32, ///< 32-bit XCOFF object file + xcoff_object_64, ///< 64-bit XCOFF object file wasm_object, ///< WebAssembly Object file pdb, ///< Windows PDB debug info file }; diff --git a/llvm/include/llvm/Object/Binary.h b/llvm/include/llvm/Object/Binary.h --- a/llvm/include/llvm/Object/Binary.h +++ b/llvm/include/llvm/Object/Binary.h @@ -51,7 +51,9 @@ // Object and children. ID_StartObjects, ID_COFF, + ID_XCOFF32, // AIX XCOFF 32-bit + ID_XCOFF64, // AIX XCOFF 64-bit ID_ELF32L, // ELF 32-bit, little endian ID_ELF32B, // ELF 32-bit, big endian @@ -121,7 +123,7 @@ return TypeID == ID_COFF; } - bool isXCOFF() const { return TypeID == ID_XCOFF32; } + bool isXCOFF() const { return TypeID == ID_XCOFF32 || TypeID == ID_XCOFF64; } bool isWasm() const { return TypeID == ID_Wasm; } diff --git a/llvm/include/llvm/Object/ObjectFile.h b/llvm/include/llvm/Object/ObjectFile.h --- a/llvm/include/llvm/Object/ObjectFile.h +++ b/llvm/include/llvm/Object/ObjectFile.h @@ -359,7 +359,7 @@ createCOFFObjectFile(MemoryBufferRef Object); static Expected> - createXCOFFObjectFile(MemoryBufferRef Object); + createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType); static Expected> createELFObjectFile(MemoryBufferRef Object); diff --git a/llvm/include/llvm/Object/XCOFFObjectFile.h b/llvm/include/llvm/Object/XCOFFObjectFile.h --- a/llvm/include/llvm/Object/XCOFFObjectFile.h +++ b/llvm/include/llvm/Object/XCOFFObjectFile.h @@ -34,7 +34,7 @@ namespace llvm { namespace object { -struct XCOFFFileHeader { +struct XCOFFFileHeader32 { support::ubig16_t Magic; support::ubig16_t NumberOfSections; @@ -48,7 +48,21 @@ support::ubig16_t Flags; }; -struct XCOFFSectionHeader { +struct XCOFFFileHeader64 { + support::ubig16_t Magic; + support::ubig16_t NumberOfSections; + + // Unix time value, value of 0 indicates no timestamp. + // Negative values are reserved. + support::big32_t TimeStamp; + + support::ubig64_t SymbolTableOffset; // File offset to symbol table. + support::ubig16_t AuxHeaderSize; + support::ubig16_t Flags; + support::ubig32_t NumberOfSymTableEntries; +}; + +struct XCOFFSectionHeader32 { char Name[XCOFF::SectionNameSize]; support::ubig32_t PhysicalAddress; support::ubig32_t VirtualAddress; @@ -59,6 +73,24 @@ support::ubig16_t NumberOfRelocations; support::ubig16_t NumberOfLineNumbers; support::big32_t Flags; + + StringRef getName() const; +}; + +struct XCOFFSectionHeader64 { + char Name[XCOFF::SectionNameSize]; + support::ubig64_t PhysicalAddress; + support::ubig64_t VirtualAddress; + support::ubig64_t SectionSize; + support::big64_t FileOffsetToRawData; + support::big64_t FileOffsetToRelocationInfo; + support::big64_t FileOffsetToLineNumberInfo; + support::ubig32_t NumberOfRelocations; + support::ubig32_t NumberOfLineNumbers; + support::big32_t Flags; + char Padding[4]; + + StringRef getName() const; }; struct XCOFFSymbolEntry { @@ -97,18 +129,35 @@ class XCOFFObjectFile : public ObjectFile { private: - const XCOFFFileHeader *FileHdrPtr = nullptr; - const XCOFFSectionHeader *SectionHdrTablePtr = nullptr; + const void *FileHeader = nullptr; + const void *SectionHeaderTable = nullptr; + const XCOFFSymbolEntry *SymbolTblPtr = nullptr; XCOFFStringTable StringTable = {0, nullptr}; + const XCOFFFileHeader32 *fileHeader32() const; + const XCOFFFileHeader64 *fileHeader64() const; + + const XCOFFSectionHeader32 *sectionHeaderTable32() const; + const XCOFFSectionHeader64 *sectionHeaderTable64() const; + size_t getFileHeaderSize() const; size_t getSectionHeaderSize() const; - const XCOFFSectionHeader *toSection(DataRefImpl Ref) const; + const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const; + const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const; + void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const; + uintptr_t getSectionHeaderTableAddress() const; + + // This returns a pointer to the start of the storage for the name field of + // the 32-bit or 64-bit SectionHeader struct. This string is *not* necessarily + // null-terminated. + const char *getSectionNameInternal(DataRefImpl Sec) const; + + uint32_t getSectionFlags(DataRefImpl Sec) const; + static bool isReservedSectionNumber(int16_t SectionNumber); - std::error_code getSectionByNum(int16_t Num, - const XCOFFSectionHeader *&Result) const; + Expected getSectionByNum(int16_t Num) const; public: void moveSymbolNext(DataRefImpl &Symb) const override; @@ -156,9 +205,10 @@ Expected getStartAddress() const override; bool isRelocatableObject() const override; - XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC); + XCOFFObjectFile(unsigned Type, MemoryBufferRef Object, std::error_code &EC); + + bool is64Bit() const; - const XCOFFFileHeader *getFileHeader() const { return FileHdrPtr; } const XCOFFSymbolEntry *getPointerToSymbolTable() const { return SymbolTblPtr; } @@ -167,19 +217,31 @@ getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const; const XCOFFSymbolEntry *toSymbolEntry(DataRefImpl Ref) const; + + // File header related interfaces. uint16_t getMagic() const; uint16_t getNumberOfSections() const; int32_t getTimeStamp() const; - uint32_t getSymbolTableOffset() const; - // Returns the value as encoded in the object file. - // Negative values are reserved for future use. - int32_t getRawNumberOfSymbolTableEntries() const; + // Symbol table offset and entry count are handled differently between + // XCOFF32 and XCOFF64. + uint32_t getSymbolTableOffset32() const; + uint64_t getSymbolTableOffset64() const; + + // Note that this value is signed and might return a negative value. Negative + // values are reserved for future use. + int32_t getRawNumberOfSymbolTableEntries32() const; + // The sanitized value appropriate to use an index into the symbol table. + uint32_t getLogicalNumberOfSymbolTableEntries32() const; + + uint32_t getNumberOfSymbolTableEntries64() const; - // Returns a sanitized value, useable as an index into the symbol table. - uint32_t getLogicalNumberOfSymbolTableEntries() const; uint16_t getOptionalHeaderSize() const; - uint16_t getFlags() const { return FileHdrPtr->Flags; }; + uint16_t getFlags() const; + + // Section header table related interfaces. + ArrayRef sections32() const; + ArrayRef sections64() const; }; // XCOFFObjectFile } // namespace object diff --git a/llvm/lib/BinaryFormat/Magic.cpp b/llvm/lib/BinaryFormat/Magic.cpp --- a/llvm/lib/BinaryFormat/Magic.cpp +++ b/llvm/lib/BinaryFormat/Magic.cpp @@ -66,6 +66,8 @@ // XCOFF format if (startswith(Magic, "\x01\xDF")) return file_magic::xcoff_object_32; + if (startswith(Magic, "\x01\xF7")) + return file_magic::xcoff_object_64; break; case 0xDE: // 0x0B17C0DE = BC wraper diff --git a/llvm/lib/Object/Binary.cpp b/llvm/lib/Object/Binary.cpp --- a/llvm/lib/Object/Binary.cpp +++ b/llvm/lib/Object/Binary.cpp @@ -70,6 +70,7 @@ case file_magic::pecoff_executable: case file_magic::bitcode: case file_magic::xcoff_object_32: + case file_magic::xcoff_object_64: case file_magic::wasm_object: return ObjectFile::createSymbolicFile(Buffer, Type, Context); case file_magic::macho_universal_binary: diff --git a/llvm/lib/Object/ObjectFile.cpp b/llvm/lib/Object/ObjectFile.cpp --- a/llvm/lib/Object/ObjectFile.cpp +++ b/llvm/lib/Object/ObjectFile.cpp @@ -150,7 +150,9 @@ case file_magic::pecoff_executable: return createCOFFObjectFile(Object); case file_magic::xcoff_object_32: - return createXCOFFObjectFile(Object); + return createXCOFFObjectFile(Object, Binary::ID_XCOFF32); + case file_magic::xcoff_object_64: + return createXCOFFObjectFile(Object, Binary::ID_XCOFF64); case file_magic::wasm_object: return createWasmObjectFile(Object); } diff --git a/llvm/lib/Object/SymbolicFile.cpp b/llvm/lib/Object/SymbolicFile.cpp --- a/llvm/lib/Object/SymbolicFile.cpp +++ b/llvm/lib/Object/SymbolicFile.cpp @@ -70,6 +70,7 @@ case file_magic::macho_kext_bundle: case file_magic::pecoff_executable: case file_magic::xcoff_object_32: + case file_magic::xcoff_object_64: case file_magic::wasm_object: return ObjectFile::createObjectFile(Object, Type); case file_magic::coff_import_library: diff --git a/llvm/lib/Object/XCOFFObjectFile.cpp b/llvm/lib/Object/XCOFFObjectFile.cpp --- a/llvm/lib/Object/XCOFFObjectFile.cpp +++ b/llvm/lib/Object/XCOFFObjectFile.cpp @@ -22,10 +22,6 @@ namespace llvm { namespace object { -enum { XCOFF32FileHeaderSize = 20 }; -static_assert(sizeof(XCOFFFileHeader) == XCOFF32FileHeaderSize, - "Wrong size for XCOFF file header."); - // Sets EC and returns false if there is less than 'Size' bytes left in the // buffer at 'Offset'. static bool checkSize(MemoryBufferRef M, std::error_code &EC, uint64_t Offset, @@ -50,6 +46,11 @@ return std::error_code(); } +static uintptr_t getWithOffset(uintptr_t Base, ptrdiff_t Offset) { + return reinterpret_cast(reinterpret_cast(Base) + + Offset); +} + template static const T *viewAs(uintptr_t in) { return reinterpret_cast(in); } @@ -60,48 +61,77 @@ : StringRef(Name, Size); } -const XCOFFSectionHeader *XCOFFObjectFile::toSection(DataRefImpl Ref) const { - auto Sec = viewAs(Ref.p); -#ifndef NDEBUG - if (Sec < SectionHdrTablePtr || - Sec >= (SectionHdrTablePtr + getNumberOfSections())) +void XCOFFObjectFile::checkSectionAddress(uintptr_t Addr, + uintptr_t TableAddress) const { + if (Addr < TableAddress || + Addr >= getWithOffset(TableAddress, + getSectionHeaderSize() * getNumberOfSections())) report_fatal_error("Section header outside of section header table."); - uintptr_t Offset = uintptr_t(Sec) - uintptr_t(SectionHdrTablePtr); + uintptr_t Offset = Addr - TableAddress; if (Offset % getSectionHeaderSize() != 0) report_fatal_error( "Section header pointer does not point to a valid section header."); +} + +const XCOFFSectionHeader32 * +XCOFFObjectFile::toSection32(DataRefImpl Ref) const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); +#ifndef NDEBUG + checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); +#endif + return viewAs(Ref.p); +} + +const XCOFFSectionHeader64 * +XCOFFObjectFile::toSection64(DataRefImpl Ref) const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); +#ifndef NDEBUG + checkSectionAddress(Ref.p, getSectionHeaderTableAddress()); #endif - return Sec; + return viewAs(Ref.p); } const XCOFFSymbolEntry *XCOFFObjectFile::toSymbolEntry(DataRefImpl Ref) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); assert(Ref.p != 0 && "Symbol table pointer can not be nullptr!"); auto SymEntPtr = viewAs(Ref.p); return SymEntPtr; } -// The next 2 functions are not exactly necessary yet, but they are useful to -// abstract over the size difference between XCOFF32 and XCOFF64 structure -// definitions. -size_t XCOFFObjectFile::getFileHeaderSize() const { - return sizeof(XCOFFFileHeader); +const XCOFFFileHeader32 *XCOFFObjectFile::fileHeader32() const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); + return static_cast(FileHeader); } -size_t XCOFFObjectFile::getSectionHeaderSize() const { - return sizeof(XCOFFSectionHeader); +const XCOFFFileHeader64 *XCOFFObjectFile::fileHeader64() const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); + return static_cast(FileHeader); +} + +const XCOFFSectionHeader32 * +XCOFFObjectFile::sectionHeaderTable32() const { + assert(!is64Bit() && "32-bit interface called on 64-bit object file."); + return static_cast(SectionHeaderTable); } -uint16_t XCOFFObjectFile::getMagic() const { return FileHdrPtr->Magic; } +const XCOFFSectionHeader64 * +XCOFFObjectFile::sectionHeaderTable64() const { + assert(is64Bit() && "64-bit interface called on a 32-bit object file."); + return static_cast(SectionHeaderTable); +} void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); SymEntPtr += SymEntPtr->NumberOfAuxEntries + 1; Symb.p = reinterpret_cast(SymEntPtr); + return; } Expected XCOFFObjectFile::getSymbolName(DataRefImpl Symb) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); if (SymEntPtr->NameInStrTbl.Magic != XCOFFSymbolEntry::NAME_IN_STR_TBL_MAGIC) @@ -135,6 +165,7 @@ } uint64_t XCOFFObjectFile::getSymbolValueImpl(DataRefImpl Symb) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); return toSymbolEntry(Symb)->Value; } @@ -152,20 +183,18 @@ Expected XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); const XCOFFSymbolEntry *SymEntPtr = toSymbolEntry(Symb); int16_t SectNum = SymEntPtr->SectionNumber; if (isReservedSectionNumber(SectNum)) return section_end(); - const XCOFFSectionHeader *Sec; - if (std::error_code EC = getSectionByNum(SectNum, Sec)) - return errorCodeToError(EC); - - DataRefImpl SecDRI; - SecDRI.p = reinterpret_cast(Sec); + Expected ExpSec = getSectionByNum(SectNum); + if (!ExpSec) + return ExpSec.takeError(); - return section_iterator(SectionRef(SecDRI, this)); + return section_iterator(SectionRef(ExpSec.get(), this)); } void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { @@ -173,26 +202,27 @@ Sec.p = reinterpret_cast(Ptr + getSectionHeaderSize()); } -Expected XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { - const char *Name = toSection(Sec)->Name; - auto NulCharPtr = - static_cast(memchr(Name, '\0', XCOFF::SectionNameSize)); - return NulCharPtr ? StringRef(Name, NulCharPtr - Name) - : StringRef(Name, XCOFF::SectionNameSize); + Expected XCOFFObjectFile::getSectionName(DataRefImpl Sec) const { + return generateStringRef(getSectionNameInternal(Sec), XCOFF::SectionNameSize); } uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { - return toSection(Sec)->VirtualAddress; + return is64Bit() ? toSection64(Sec)->VirtualAddress + : toSection32(Sec)->VirtualAddress; } uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { // Section numbers in XCOFF are numbered beginning at 1. A section number of // zero is used to indicate that a symbol is being imported or is undefined. - return toSection(Sec) - SectionHdrTablePtr + 1; + if (is64Bit()) + return toSection64(Sec) - sectionHeaderTable64() + 1; + else + return toSection32(Sec) - sectionHeaderTable32() + 1; } uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const { - return toSection(Sec)->SectionSize; + return is64Bit() ? toSection64(Sec)->SectionSize + : toSection32(Sec)->SectionSize; } Expected> @@ -213,16 +243,16 @@ } bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { - return toSection(Sec)->Flags & XCOFF::STYP_TEXT; + return getSectionFlags(Sec) & XCOFF::STYP_TEXT; } bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { - unsigned Flags = toSection(Sec)->Flags; + uint32_t Flags = getSectionFlags(Sec); return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); } bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { - unsigned Flags = toSection(Sec)->Flags; + uint32_t Flags = getSectionFlags(Sec); return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); } @@ -277,45 +307,41 @@ } basic_symbol_iterator XCOFFObjectFile::symbol_begin() const { + assert(!is64Bit() && "64-bit support not implemented yet."); DataRefImpl SymDRI; SymDRI.p = reinterpret_cast(SymbolTblPtr); return basic_symbol_iterator(SymbolRef(SymDRI, this)); } basic_symbol_iterator XCOFFObjectFile::symbol_end() const { + assert(!is64Bit() && "64-bit support not implemented yet."); DataRefImpl SymDRI; SymDRI.p = reinterpret_cast( - SymbolTblPtr + getLogicalNumberOfSymbolTableEntries()); + SymbolTblPtr + getLogicalNumberOfSymbolTableEntries32()); return basic_symbol_iterator(SymbolRef(SymDRI, this)); } section_iterator XCOFFObjectFile::section_begin() const { DataRefImpl DRI; - DRI.p = reinterpret_cast(SectionHdrTablePtr); + DRI.p = getSectionHeaderTableAddress(); return section_iterator(SectionRef(DRI, this)); } section_iterator XCOFFObjectFile::section_end() const { DataRefImpl DRI; - DRI.p = - reinterpret_cast(SectionHdrTablePtr + getNumberOfSections()); + DRI.p = getWithOffset(getSectionHeaderTableAddress(), + getNumberOfSections() * getSectionHeaderSize()); return section_iterator(SectionRef(DRI, this)); } -uint8_t XCOFFObjectFile::getBytesInAddress() const { - // Only support 32-bit object files for now ... - assert(getFileHeaderSize() == XCOFF32FileHeaderSize); - return 4; -} +uint8_t XCOFFObjectFile::getBytesInAddress() const { return is64Bit() ? 8 : 4; } StringRef XCOFFObjectFile::getFileFormatName() const { - assert(getFileHeaderSize() == XCOFF32FileHeaderSize); - return "aixcoff-rs6000"; + return is64Bit() ? "aix5coff64-rs6000" : "aixcoff-rs6000"; } Triple::ArchType XCOFFObjectFile::getArch() const { - assert(getFileHeaderSize() == XCOFF32FileHeaderSize); - return Triple::ppc; + return is64Bit() ? Triple::ppc64 : Triple::ppc; } SubtargetFeatures XCOFFObjectFile::getFeatures() const { @@ -335,19 +361,36 @@ return 0; } -std::error_code -XCOFFObjectFile::getSectionByNum(int16_t Num, - const XCOFFSectionHeader *&Result) const { - if (Num > 0 && static_cast(Num) <= getNumberOfSections()) { - Result = SectionHdrTablePtr + (Num - 1); - return std::error_code(); - } +size_t XCOFFObjectFile::getFileHeaderSize() const { + return is64Bit() ? sizeof(XCOFFFileHeader64) : sizeof(XCOFFFileHeader32); +} + +size_t XCOFFObjectFile::getSectionHeaderSize() const { + return is64Bit() ? sizeof(XCOFFSectionHeader64) : + sizeof(XCOFFSectionHeader32); +} + +bool XCOFFObjectFile::is64Bit() const { + return Binary::ID_XCOFF64 == getType(); +} + +uint16_t XCOFFObjectFile::getMagic() const { + return is64Bit() ? fileHeader64()->Magic : fileHeader32()->Magic; +} - return object_error::invalid_section_index; +Expected XCOFFObjectFile::getSectionByNum(int16_t Num) const { + if (Num <= 0 || Num > getNumberOfSections()) + return errorCodeToError(object_error::invalid_section_index); + + DataRefImpl DRI; + DRI.p = getWithOffset(getSectionHeaderTableAddress(), + getSectionHeaderSize() * (Num - 1)); + return DRI; } Expected XCOFFObjectFile::getSymbolSectionName(const XCOFFSymbolEntry *SymEntPtr) const { + assert(!is64Bit() && "Symbol table support not implemented for 64-bit."); int16_t SectionNum = SymEntPtr->SectionNumber; switch (SectionNum) { @@ -357,14 +400,12 @@ return "N_ABS"; case XCOFF::N_UNDEF: return "N_UNDEF"; - default: { - const XCOFFSectionHeader *SectHeaderPtr; - std::error_code EC; - if ((EC = getSectionByNum(SectionNum, SectHeaderPtr))) - return errorCodeToError(EC); - else - return generateStringRef(SectHeaderPtr->Name, XCOFF::SectionNameSize); - } + default: + Expected SI = getSectionByNum(SectionNum); + if (SI) + return generateStringRef(getSectionNameInternal(SI.get()), + XCOFF::SectionNameSize); + return SI.takeError(); } } @@ -373,56 +414,93 @@ } uint16_t XCOFFObjectFile::getNumberOfSections() const { - return FileHdrPtr->NumberOfSections; + return is64Bit() ? fileHeader64()->NumberOfSections + : fileHeader32()->NumberOfSections; +} + +int32_t XCOFFObjectFile::getTimeStamp() const { + return is64Bit() ? fileHeader64()->TimeStamp : fileHeader32()->TimeStamp; } -int32_t XCOFFObjectFile::getTimeStamp() const { return FileHdrPtr->TimeStamp; } +uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { + return is64Bit() ? fileHeader64()->AuxHeaderSize + : fileHeader32()->AuxHeaderSize; +} -uint32_t XCOFFObjectFile::getSymbolTableOffset() const { - return FileHdrPtr->SymbolTableOffset; +uint32_t XCOFFObjectFile::getSymbolTableOffset32() const { + return fileHeader32()->SymbolTableOffset; } -int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries() const { - return FileHdrPtr->NumberOfSymTableEntries; +int32_t XCOFFObjectFile::getRawNumberOfSymbolTableEntries32() const { + // As far as symbol table size is concerned, if this field is negative it is + // to be treated as a 0. However since this field is also used for printing we + // don't want to truncate any negative values. + return fileHeader32()->NumberOfSymTableEntries; } -uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries() const { - return (FileHdrPtr->NumberOfSymTableEntries >= 0 - ? FileHdrPtr->NumberOfSymTableEntries +uint32_t XCOFFObjectFile::getLogicalNumberOfSymbolTableEntries32() const { + return (fileHeader32()->NumberOfSymTableEntries >= 0 + ? fileHeader32()->NumberOfSymTableEntries : 0); } -uint16_t XCOFFObjectFile::getOptionalHeaderSize() const { - return FileHdrPtr->AuxHeaderSize; +uint64_t XCOFFObjectFile::getSymbolTableOffset64() const { + return fileHeader64()->SymbolTableOffset; } -XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC) - : ObjectFile(Binary::ID_XCOFF32, Object) { +uint32_t XCOFFObjectFile::getNumberOfSymbolTableEntries64() const { + return fileHeader64()->NumberOfSymTableEntries; +} + +uint16_t XCOFFObjectFile::getFlags() const { + return is64Bit() ? fileHeader64()->Flags : fileHeader32()->Flags; +} + +const char *XCOFFObjectFile::getSectionNameInternal(DataRefImpl Sec) const { + return is64Bit() ? toSection64(Sec)->Name : toSection32(Sec)->Name; +} + +uintptr_t XCOFFObjectFile::getSectionHeaderTableAddress() const { + return reinterpret_cast(SectionHeaderTable); +} + +uint32_t XCOFFObjectFile::getSectionFlags(DataRefImpl Sec) const { + return is64Bit() ? toSection64(Sec)->Flags : toSection32(Sec)->Flags; +} + +XCOFFObjectFile::XCOFFObjectFile(unsigned int Type, MemoryBufferRef Object, + std::error_code &EC) + : ObjectFile(Type, Object) { + assert(Type == Binary::ID_XCOFF32 || Type == Binary::ID_XCOFF64); // Current location within the file. uint64_t CurPtr = 0; - - if ((EC = getObject(FileHdrPtr, Data, base() + CurPtr))) + if (EC = getObject(FileHeader, Data, base() + CurPtr, getFileHeaderSize())) return; CurPtr += getFileHeaderSize(); // TODO FIXME we don't have support for an optional header yet, so just skip // past it. - CurPtr += FileHdrPtr->AuxHeaderSize; + CurPtr += getOptionalHeaderSize(); if (getNumberOfSections() != 0) { - if ((EC = getObject(SectionHdrTablePtr, Data, base() + CurPtr, + if ((EC = getObject(SectionHeaderTable, Data, base() + CurPtr, getNumberOfSections() * getSectionHeaderSize()))) return; } - if (getLogicalNumberOfSymbolTableEntries() == 0) + // Support for the symbol table and string table parsing is limited to 32-bit + // object files for now. + if (is64Bit()) + return; + + if (getLogicalNumberOfSymbolTableEntries32() == 0) return; // Get pointer to the symbol table. - CurPtr = FileHdrPtr->SymbolTableOffset; + CurPtr = fileHeader32()->SymbolTableOffset; uint64_t SymbolTableSize = (uint64_t)(sizeof(XCOFFSymbolEntry)) * - getLogicalNumberOfSymbolTableEntries(); + getLogicalNumberOfSymbolTableEntries32(); if ((EC = getObject(SymbolTblPtr, Data, base() + CurPtr, SymbolTableSize))) return; @@ -450,23 +528,42 @@ } } +ArrayRef XCOFFObjectFile::sections64() const { + assert(is64Bit() && "64-bit interface called for non 64-bit file."); + const XCOFFSectionHeader64 *TablePtr = sectionHeaderTable64(); + return ArrayRef( + TablePtr, TablePtr + getNumberOfSections()); +} + +ArrayRef XCOFFObjectFile::sections32() const { + assert(!is64Bit() && "32-bit interface called for non 32-bit file."); + const XCOFFSectionHeader32 *TablePtr = sectionHeaderTable32(); + return ArrayRef( + TablePtr, TablePtr + getNumberOfSections()); +} + Expected> -ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object) { - StringRef Data = Object.getBuffer(); - file_magic Type = identify_magic(Data); +ObjectFile::createXCOFFObjectFile(MemoryBufferRef Object, unsigned FileType) { std::error_code EC; std::unique_ptr Ret; - if (Type == file_magic::xcoff_object_32) { - Ret.reset(new XCOFFObjectFile(Object, EC)); - } else { - llvm_unreachable("Encountered an unexpected binary file type!"); - } + assert((FileType == Binary::ID_XCOFF32 || FileType == Binary::ID_XCOFF64) && + "Non-XCOFF file type passed to createXCOFFObjectFile!"); + + Ret.reset(new XCOFFObjectFile(FileType, Object, EC)); if (EC) return errorCodeToError(EC); return std::move(Ret); } +StringRef XCOFFSectionHeader32::getName() const { + return generateStringRef(Name, XCOFF::SectionNameSize); +} + +StringRef XCOFFSectionHeader64::getName() const { + return generateStringRef(Name, XCOFF::SectionNameSize); +} + } // namespace object } // namespace llvm diff --git a/llvm/test/tools/llvm-readobj/xcoff-basic.test b/llvm/test/tools/llvm-readobj/xcoff-basic.test --- a/llvm/test/tools/llvm-readobj/xcoff-basic.test +++ b/llvm/test/tools/llvm-readobj/xcoff-basic.test @@ -1,5 +1,8 @@ # RUN: llvm-readobj --file-header %p/Inputs/xcoff-basic.o | \ # RUN: FileCheck --check-prefix=FILEHEADER %s +# +# RUN: llvm-readobj --file-header %p/Inputs/xcoff-basic-64.o | \ +# RUN: FileCheck --check-prefix=FILEHEADER64 %s # RUN: llvm-readobj --file-header %p/Inputs/xcoff-basic-neg-time.o | \ # RUN: FileCheck --check-prefix=NEGTIME %s @@ -21,6 +24,20 @@ # FILEHEADER-NEXT: Flags: 0x0 # FILEHEADER-NEXT: } +# FILEHEADER64: File: {{.*}}xcoff-basic-64.o +# FILEHEADER64-NEXT: Format: aix5coff64-rs6000 +# FILEHEADER64-NEXT: Arch: powerpc64 +# FILEHEADER64-NEXT: AddressSize: 64bit +# FILEHEADER64-NEXT: FileHeader { +# FILEHEADER64-NEXT: Magic: 0x1F7 +# FILEHEADER64-NEXT: NumberOfSections: 5 +# FILEHEADER64-NEXT: TimeStamp: 2019-03-18T20:03:47Z (0x5C8FF9A3) +# FILEHEADER64-NEXT: SymbolTableOffset: 0x54C +# FILEHEADER64-NEXT: SymbolTableEntries: 58 +# FILEHEADER64-NEXT: OptionalHeaderSize: 0x0 +# FILEHEADER64-NEXT: Flags: 0x0 +# FILEHEADER64-NEXT: } + # NEGTIME: File: {{.*}}xcoff-basic-neg-time.o # NEGTIME-NEXT: Format: aixcoff-rs6000 # NEGTIME-NEXT: Arch: powerpc diff --git a/llvm/tools/llvm-readobj/XCOFFDumper.cpp b/llvm/tools/llvm-readobj/XCOFFDumper.cpp --- a/llvm/tools/llvm-readobj/XCOFFDumper.cpp +++ b/llvm/tools/llvm-readobj/XCOFFDumper.cpp @@ -36,6 +36,8 @@ void printNeededLibraries() override; private: + template void printSectionHeaders(ArrayRef Sections); + const XCOFFObjectFile &Obj; }; } // anonymous namespace @@ -65,12 +67,20 @@ TimeStamp); } - W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset()); - int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries(); - if (SymTabEntries >= 0) - W.printNumber("SymbolTableEntries", SymTabEntries); - else - W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries); + // The number of symbol table entries is an unsigned value in 64-bit objects + // and a signed value (with negative values being 'reserved') in 32-bit + // objects. + if (Obj.is64Bit()) { + W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset64()); + W.printNumber("SymbolTableEntries", Obj.getNumberOfSymbolTableEntries64()); + } else { + W.printHex("SymbolTableOffset", Obj.getSymbolTableOffset32()); + int32_t SymTabEntries = Obj.getRawNumberOfSymbolTableEntries32(); + if (SymTabEntries >= 0) + W.printNumber("SymbolTableEntries", SymTabEntries); + else + W.printHex("SymbolTableEntries", "Reserved Value", SymTabEntries); + } W.printHex("OptionalHeaderSize", Obj.getOptionalHeaderSize()); W.printHex("Flags", Obj.getFlags()); @@ -80,7 +90,10 @@ } void XCOFFDumper::printSectionHeaders() { - llvm_unreachable("Unimplemented functionality for XCOFFDumper"); + if (Obj.is64Bit()) + printSectionHeaders(Obj.sections64()); + else + printSectionHeaders(Obj.sections32()); } void XCOFFDumper::printRelocations() { @@ -107,6 +120,38 @@ llvm_unreachable("Unimplemented functionality for XCOFFDumper"); } +template +void XCOFFDumper::printSectionHeaders(ArrayRef Sections) { + ListScope Group(W, "Sections"); + + uint16_t Index = 1; + for (const T &Sec : Sections) { + DictScope SecDS(W, "Section"); + + W.printNumber("Index", Index++); + W.printString("Name", Sec.getName()); + + W.printHex("PhysicalAddress", Sec.PhysicalAddress); + W.printHex("VirtualAddress", Sec.VirtualAddress); + W.printHex("Size", Sec.SectionSize); + W.printHex("RawDataOffset", Sec.FileOffsetToRawData); + W.printHex("RelocationPointer", Sec.FileOffsetToRelocationInfo); + W.printHex("LineNumberPointer", Sec.FileOffsetToLineNumberInfo); + W.printNumber("NumberOfRelocations", Sec.NumberOfRelocations); + W.printNumber("NumberOfLineNumbers", Sec.NumberOfLineNumbers); + W.printHex("Flags", Sec.Flags); + } + + if (opts::SectionRelocations) + llvm_unreachable("Dumping section relocations is unimplemented"); + + if (opts::SectionSymbols) + llvm_unreachable("Dumping symbols is unimplemented"); + + if (opts::SectionData) + llvm_unreachable("Dumping section data is unimplemented"); +} + namespace llvm { std::error_code createXCOFFDumper(const object::ObjectFile *Obj, ScopedPrinter &Writer, diff --git a/llvm/tools/obj2yaml/xcoff2yaml.cpp b/llvm/tools/obj2yaml/xcoff2yaml.cpp --- a/llvm/tools/obj2yaml/xcoff2yaml.cpp +++ b/llvm/tools/obj2yaml/xcoff2yaml.cpp @@ -29,22 +29,25 @@ } // namespace std::error_code XCOFFDumper::dump() { - std::error_code EC; dumpHeader(); - EC = dumpSymbols(); - return EC; + return dumpSymbols(); } void XCOFFDumper::dumpHeader() { - const XCOFFFileHeader *FileHdrPtr = Obj.getFileHeader(); - - YAMLObj.Header.Magic = FileHdrPtr->Magic; - YAMLObj.Header.NumberOfSections = FileHdrPtr->NumberOfSections; - YAMLObj.Header.TimeStamp = FileHdrPtr->TimeStamp; - YAMLObj.Header.SymbolTableOffset = FileHdrPtr->SymbolTableOffset; - YAMLObj.Header.NumberOfSymTableEntries = FileHdrPtr->NumberOfSymTableEntries; - YAMLObj.Header.AuxHeaderSize = FileHdrPtr->AuxHeaderSize; - YAMLObj.Header.Flags = FileHdrPtr->Flags; + + YAMLObj.Header.Magic = Obj.getMagic(); + YAMLObj.Header.NumberOfSections = Obj.getNumberOfSections(); + YAMLObj.Header.TimeStamp = Obj.getTimeStamp(); + + // TODO FIXME only dump 32 bit header for now. + if (Obj.is64Bit()) + report_fatal_error("64-bit XCOFF files not suported yet."); + YAMLObj.Header.SymbolTableOffset = Obj.getSymbolTableOffset32(); + + YAMLObj.Header.NumberOfSymTableEntries = + Obj.getRawNumberOfSymbolTableEntries32(); + YAMLObj.Header.AuxHeaderSize = Obj.getOptionalHeaderSize(); + YAMLObj.Header.Flags = Obj.getFlags(); } std::error_code XCOFFDumper::dumpSymbols() {