From a93a33cb87ec21da20b6c7080c25fdd41e225cec Mon Sep 17 00:00:00 2001 From: Sean Fertile Date: Thu, 25 Apr 2019 21:36:04 +0000 Subject: [PATCH] [Object][XCOFF] Add intial support for section header table. Adds a representation of the section header table to XCOFFObjectFile, and implements enough to dump the section headers with llvm-obdump. Differential Revision: https://reviews.llvm.org/D60784 llvm-svn: 359244 --- llvm/include/llvm/BinaryFormat/XCOFF.h | 43 +++++++ llvm/include/llvm/Object/XCOFFObjectFile.h | 25 +++- llvm/lib/Object/XCOFFObjectFile.cpp | 112 +++++++++++++----- .../Inputs/xcoff-long-sec-names.o | Bin 0 -> 296 bytes .../Inputs/xcoff-section-headers-truncate.o | Bin 0 -> 200 bytes .../Inputs/xcoff-section-headers.o | Bin 0 -> 1549 bytes .../llvm-objdump/xcoff-section-headers.test | 43 +++++++ 7 files changed, 192 insertions(+), 31 deletions(-) create mode 100644 llvm/include/llvm/BinaryFormat/XCOFF.h create mode 100644 llvm/test/tools/llvm-objdump/Inputs/xcoff-long-sec-names.o create mode 100644 llvm/test/tools/llvm-objdump/Inputs/xcoff-section-headers-truncate.o create mode 100644 llvm/test/tools/llvm-objdump/Inputs/xcoff-section-headers.o create mode 100644 llvm/test/tools/llvm-objdump/xcoff-section-headers.test diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h new file mode 100644 index 000000000000..32c0232f6e50 --- /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 index 4689b3f085a9..f35b36e94893 100644 --- 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 @@ struct XCOFFFileHeader { 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 @@ public: 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 index 2903251492b0..e74085575a67 100644 --- 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 @@ static std::error_code getObject(const T *&Obj, MemoryBufferRef M, 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 @@ XCOFFObjectFile::getSymbolSection(DataRefImpl Symb) const { } 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::isSectionCompressed(DataRefImpl Sec) const { } 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 @@ basic_symbol_iterator XCOFFObjectFile::symbol_end() const { } 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 @@ uint8_t XCOFFObjectFile::getBytesInAddress() const { } 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 @@ bool XCOFFObjectFile::isRelocatableObject() const { 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 @@ XCOFFObjectFile::XCOFFObjectFile(MemoryBufferRef Object, std::error_code &EC) 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..3dfc498babf0e1a1be36472372ab3c25f7c19d6f GIT binary patch literal 296 zcmZR)&%hkBW>+Tz1H%j;<^W;_y_E9AqP+A}5E}|ufOHRx1EyIS1c2%alJatkk;Fmj zCLr+{7?`2zN-7JG#6jw&An_R(SQrG5`Fd%YIWPzO|Hs3e&X|&#RGO}bY#E9>85tM~ VfEZ{F3P5oq6CO1%_c3Ev0|41NAp`&b literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-objdump/Inputs/xcoff-section-headers-truncate.o b/llvm/test/tools/llvm-objdump/Inputs/xcoff-section-headers-truncate.o new file mode 100644 index 0000000000000000000000000000000000000000..7667c6f791c990be80dbd697a7a87d90a9cfea46 GIT binary patch literal 200 zcmZR)&%hcJ@zI2VfhC23fx&@6hJk^R8^~f{1Q9Vn%mQLS03(B5Noqw2j0>hg>X?9- zIRQv8FmQlL1-+ESl0+~QBo8x-8OUbd02USklMZ@G#l>J210&Eb5Jt8SA_F8F^h)3c P!UTctVg{-QyPE+3eaa78 literal 0 HcmV?d00001 diff --git a/llvm/test/tools/llvm-objdump/Inputs/xcoff-section-headers.o b/llvm/test/tools/llvm-objdump/Inputs/xcoff-section-headers.o new file mode 100644 index 0000000000000000000000000000000000000000..0090c7d72feb9ea415c64b88d121d8f390e1aeb7 GIT binary patch literal 1549 zcmeHHJx?1!5FMWng(N761CjE9;)&!U1zO!vpqR=I6;c8XiYU_9#!gU>LB2yuxdlQl zkU~L`l7cdIlz)@IK#PO|Z)W%GJA%t}8EIzU&b)m$>)mzfH%)!~HM}4SE{W(h%@dXG z0})wx4IaWXvnK6+O|zLBE!F}BKXh8s$Y!gRwiK$41%y_BG5D$JI~p6Nog|8g&M=CH zex4uj-LarAOhXHN?c1k9GU-SVbrQctPtyNQegWI2&~}K{EV0aqxPc(2I74A?zmM8K zwiD>fxu3%G2V*gZMfJwrR~P3m4*QtMMSK3OjA-F=RRlVKKUFjYnpboL#8pN-hSwCy zcOGf=JJ91QncntJ7f|f#50yWalWr&7-t8ym=C1u6a+g~dyws=-72X6WWuaO94IK%w z@E))W<zzA;T@pnb+WRKg*PyDyG~&N`u*a1)^yz$P5$^x#DQ=g zxS||{*v9&b1F~ZzRmW#44;{$KoCrsCW?Zdu?=Q|+$M3x&=M8JQLE;%9r#hZ9i+zga zI0vJCZs@cfRpRNWpN!*ma-88Loz7Tiny{|W&l6Y7agHYGY>jpF-%54-OL#WtiaE~l zBpooD8=v>Nxi{eW4ad>);?i;y^I{a&nO5Jv=goJ#!oA%AH&-_o_(OM);I?zTWMUJU Gn63ds^&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 +# test.c: +# 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 -- 2.34.1