diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h new file mode 100644 --- /dev/null +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -0,0 +1,43 @@ +//===-- llvm/BinaryFormat/XCOFF.h - The XCOFF file format -------*- C++/-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines manifest constants for the XCOFF object file format. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_BINARYFORMAT_XCOFF_H +#define LLVM_BINARYFORMAT_XCOFF_H + +namespace llvm { +namespace XCOFF { + +// Constants used in the XCOFF definition. +enum { SectionNameSize = 8 }; + +// Flags for defining the section type. Used for the s_flags field of +// the section header structure. Defined in the system header `scnhdr.h`. +enum SectionTypeFlags { + STYP_PAD = 0x0008, + STYP_DWARF = 0x0010, + STYP_TEXT = 0x0020, + STYP_DATA = 0x0040, + STYP_BSS = 0x0080, + STYP_EXCEPT = 0x0100, + STYP_INFO = 0x0200, + STYP_TDATA = 0x0400, + STYP_TBSS = 0x0800, + STYP_LOADER = 0x1000, + STYP_DEBUG = 0x2000, + STYP_TYPCHK = 0x4000, + STYP_OVRFLO = 0x8000 +}; + +} // end namespace XCOFF +} // end namespace llvm + +#endif 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 @@ -16,6 +16,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/ADT/iterator_range.h" #include "llvm/BinaryFormat/Magic.h" +#include "llvm/BinaryFormat/XCOFF.h" #include "llvm/MC/SubtargetFeature.h" #include "llvm/Object/Binary.h" #include "llvm/Object/Error.h" @@ -47,9 +48,30 @@ support::ubig16_t Flags; }; +struct XCOFFSectionHeader { + char Name[XCOFF::SectionNameSize]; + support::ubig32_t PhysicalAddress; + support::ubig32_t VirtualAddress; + support::ubig32_t SectionSize; + support::ubig32_t FileOffsetToRawData; + support::ubig32_t FileOffsetToRelocationInfo; + support::ubig32_t FileOffsetToLineNumberInfo; + support::ubig16_t NumberOfRelocations; + support::ubig16_t NumberOfLineNumbers; + support::big32_t Flags; +}; + class XCOFFObjectFile : public ObjectFile { private: const XCOFFFileHeader *FileHdrPtr = nullptr; + const XCOFFSectionHeader *SectionHdrTablePtr = nullptr; + + size_t getFileHeaderSize() const; + size_t getSectionHeaderSize() const; + + const XCOFFSectionHeader *toSection(DataRefImpl Ref) const; + + uint16_t getNumberOfSections() const; public: void moveSymbolNext(DataRefImpl &Symb) const override; @@ -95,13 +117,12 @@ StringRef getFileFormatName() const override; Triple::ArchType getArch() const override; SubtargetFeatures getFeatures() const override; + Expected getStartAddress() const override; bool isRelocatableObject() const override; -public: XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC); const XCOFFFileHeader *getFileHeader() const { return FileHdrPtr; } - }; // XCOFFObjectFile } // namespace object 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,6 +22,10 @@ namespace llvm { namespace object { +enum { XCOFF32FileHeaderSize = 20 }; +static_assert(sizeof(XCOFFFileHeader) == XCOFF32FileHeaderSize, + "Wrong size for XCOFF file header."); + // Sets Obj unless any bytes in [addr, addr + size) fall outsize of m. // Returns unexpected_eof on error. template @@ -35,6 +39,40 @@ return std::error_code(); } +template static const T *viewAs(uintptr_t in) { + return reinterpret_cast(in); +} + +const XCOFFSectionHeader *XCOFFObjectFile::toSection(DataRefImpl Ref) const { + auto Sec = viewAs(Ref.p); +#ifndef NDEBUG + if (Sec < SectionHdrTablePtr || + Sec >= (SectionHdrTablePtr + getNumberOfSections())) + report_fatal_error("Section header outside of section header table."); + + uintptr_t Offset = uintptr_t(Sec) - uintptr_t(SectionHdrTablePtr); + if (Offset % getSectionHeaderSize() != 0) + report_fatal_error( + "Section header pointer does not point to a valid section header."); +#endif + return Sec; +} + +// 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); +} + +size_t XCOFFObjectFile::getSectionHeaderSize() const { + return sizeof(XCOFFSectionHeader); +} + +uint16_t XCOFFObjectFile::getNumberOfSections() const { + return FileHdrPtr->NumberOfSections; +} + void XCOFFObjectFile::moveSymbolNext(DataRefImpl &Symb) const { llvm_unreachable("Not yet implemented!"); return; @@ -77,32 +115,32 @@ } void XCOFFObjectFile::moveSectionNext(DataRefImpl &Sec) const { - llvm_unreachable("Not yet implemented!"); - return; + const char *Ptr = reinterpret_cast(Sec.p); + Sec.p = reinterpret_cast(Ptr + getSectionHeaderSize()); } std::error_code XCOFFObjectFile::getSectionName(DataRefImpl Sec, StringRef &Res) const { - llvm_unreachable("Not yet implemented!"); + const char *Name = toSection(Sec)->Name; + auto NulCharPtr = + static_cast(memchr(Name, '\0', XCOFF::SectionNameSize)); + Res = NulCharPtr ? StringRef(Name, NulCharPtr - Name) + : StringRef(Name, XCOFF::SectionNameSize); return std::error_code(); } uint64_t XCOFFObjectFile::getSectionAddress(DataRefImpl Sec) const { - uint64_t Result = 0; - llvm_unreachable("Not yet implemented!"); - return Result; + return toSection(Sec)->VirtualAddress; } uint64_t XCOFFObjectFile::getSectionIndex(DataRefImpl Sec) const { - uint64_t Result = 0; - llvm_unreachable("Not yet implemented!"); - return Result; + // 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; } uint64_t XCOFFObjectFile::getSectionSize(DataRefImpl Sec) const { - uint64_t Result = 0; - llvm_unreachable("Not yet implemented!"); - return Result; + return toSection(Sec)->SectionSize; } std::error_code XCOFFObjectFile::getSectionContents(DataRefImpl Sec, @@ -124,21 +162,17 @@ } bool XCOFFObjectFile::isSectionText(DataRefImpl Sec) const { - bool Result = false; - llvm_unreachable("Not yet implemented!"); - return Result; + return toSection(Sec)->Flags & XCOFF::STYP_TEXT; } bool XCOFFObjectFile::isSectionData(DataRefImpl Sec) const { - bool Result = false; - llvm_unreachable("Not yet implemented!"); - return Result; + unsigned Flags = toSection(Sec)->Flags; + return Flags & (XCOFF::STYP_DATA | XCOFF::STYP_TDATA); } bool XCOFFObjectFile::isSectionBSS(DataRefImpl Sec) const { - bool Result = false; - llvm_unreachable("Not yet implemented!"); - return Result; + unsigned Flags = toSection(Sec)->Flags; + return Flags & (XCOFF::STYP_BSS | XCOFF::STYP_TBSS); } bool XCOFFObjectFile::isSectionVirtual(DataRefImpl Sec) const { @@ -202,13 +236,16 @@ } section_iterator XCOFFObjectFile::section_begin() const { - llvm_unreachable("Not yet implemented!"); - return section_iterator(SectionRef()); + DataRefImpl DRI; + DRI.p = reinterpret_cast(SectionHdrTablePtr); + return section_iterator(SectionRef(DRI, this)); } section_iterator XCOFFObjectFile::section_end() const { - llvm_unreachable("Not yet implemented!"); - return section_iterator(SectionRef()); + DataRefImpl DRI; + DRI.p = + reinterpret_cast(SectionHdrTablePtr + getNumberOfSections()); + return section_iterator(SectionRef(DRI, this)); } uint8_t XCOFFObjectFile::getBytesInAddress() const { @@ -218,13 +255,13 @@ } StringRef XCOFFObjectFile::getFileFormatName() const { - llvm_unreachable("Not yet implemented!"); - return ""; + assert(getFileHeaderSize() == XCOFF32FileHeaderSize); + return "aixcoff-rs6000"; } Triple::ArchType XCOFFObjectFile::getArch() const { - llvm_unreachable("Not yet implemented!"); - return Triple::UnknownArch; + assert(getFileHeaderSize() == XCOFF32FileHeaderSize); + return Triple::ppc; } SubtargetFeatures XCOFFObjectFile::getFeatures() const { @@ -238,6 +275,12 @@ return Result; } +Expected XCOFFObjectFile::getStartAddress() const { + // TODO FIXME Should get from auxiliary_header->o_entry when support for the + // auxiliary_header is added. + return 0; +} + XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC) : ObjectFile(Binary::ID_XCOFF32, Object) { @@ -246,6 +289,17 @@ if ((EC = getObject(FileHdrPtr, Data, base() + CurPtr))) return; + + CurPtr += getFileHeaderSize(); + // TODO FIXME we don't have support for an optional header yet, so just skip + // past it. + CurPtr += FileHdrPtr->AuxHeaderSize; + + if (getNumberOfSections() != 0) { + if ((EC = getObject(SectionHdrTablePtr, Data, base() + CurPtr, + getNumberOfSections() * getSectionHeaderSize()))) + return; + } } Expected> diff --git a/llvm/test/tools/llvm-objdump/Inputs/xcoff-long-sec-names.o b/llvm/test/tools/llvm-objdump/Inputs/xcoff-long-sec-names.o new file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@&1 \ +# RUN: %p/Inputs/xcoff-section-headers-truncate.o | FileCheck \ +# RUN: --check-prefix=ERROR %s + +# ERROR: The end of the file was unexpectedly encountered + +# CHECK: xcoff-section-headers.o: file format aixcoff-rs6000 +# CHECK: Sections: +# CHECK: Idx Name Size VMA Type +# CHECK: 1 .text 00000080 0000000000000000 TEXT +# CHECK: 2 .data 00000024 0000000000000080 DATA +# CHECK: 3 .bss 00000004 00000000000000a4 BSS +# CHECK: 4 .tdata 00000008 0000000000000000 DATA +# CHECK: 5 .tbss 00000004 0000000000000008 BSS + +# xcoff-section-headers.o Compiled with IBM XL C/C++ for AIX, V16.1.0 +# source: +# int a; +# int b = 12345; +# __thread int c; +# __thread double d = 3.14159; +# +#int func(void) { +# return a; +#} + +# LONG: xcoff-long-sec-names.o: file format aixcoff-rs6000 +# LONG: Sections: +# LONG: Idx Name Size VMA Type +# LONG: 1 .dwarnge 00000004 0000000000000000 +# LONG: 2 .dwpbnms 00000004 0000000000000000 +# LONG: 3 .dwpbtyp 00000004 0000000000000000 + +# xcoff-long-sec-names.o was generated by assembling the following .s file: +# .dwsect 0x30000 # .dwpbnms section +# .dwsect 0x40000 # .dwpbtyp section +# .dwsect 0x50000 # .dwarnge section