diff --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h --- a/llvm/include/llvm/BinaryFormat/XCOFF.h +++ b/llvm/include/llvm/BinaryFormat/XCOFF.h @@ -26,8 +26,13 @@ constexpr size_t FileNamePadSize = 6; constexpr size_t NameSize = 8; +constexpr size_t FileHeaderSize32 = 20; +constexpr size_t FileHeaderSize64 = 24; +constexpr size_t SectionHeaderSize32 = 40; +constexpr size_t SectionHeaderSize64 = 72; constexpr size_t SymbolTableEntrySize = 18; constexpr size_t RelocationSerializationSize32 = 10; +constexpr size_t RelocationSerializationSize64 = 14; constexpr uint16_t RelocOverflow = 65535; constexpr uint8_t AllocRegNo = 31; @@ -255,29 +260,6 @@ ///< large code model TOC-relative relocation. }; -struct FileHeader32 { - uint16_t Magic; - uint16_t NumberOfSections; - int32_t TimeStamp; - uint32_t SymbolTableFileOffset; - int32_t NumberOfSymbolTableEntries; - uint16_t AuxiliaryHeaderSize; - uint16_t Flags; -}; - -struct SectionHeader32 { - char Name[XCOFF::NameSize]; - uint32_t PhysicalAddress; - uint32_t VirtualAddress; - uint32_t Size; - uint32_t FileOffsetToData; - uint32_t FileOffsetToRelocations; - uint32_t FileOffsetToLineNumbers; - uint16_t NumberOfRelocations; - uint16_t NumberOfLineNumbers; - int32_t Flags; -}; - enum CFileStringType : uint8_t { XFT_FN = 0, ///< Specifies the source-file name. XFT_CT = 1, ///< Specifies the compiler time stamp. diff --git a/llvm/lib/MC/XCOFFObjectWriter.cpp b/llvm/lib/MC/XCOFFObjectWriter.cpp --- a/llvm/lib/MC/XCOFFObjectWriter.cpp +++ b/llvm/lib/MC/XCOFFObjectWriter.cpp @@ -911,8 +911,8 @@ SymbolTableEntryCount = SymbolTableIndex; // Calculate the RawPointer value for each section. - uint64_t RawPointer = sizeof(XCOFF::FileHeader32) + auxiliaryHeaderSize() + - SectionCount * sizeof(XCOFF::SectionHeader32); + uint64_t RawPointer = XCOFF::FileHeaderSize32 + auxiliaryHeaderSize() + + SectionCount * XCOFF::SectionHeaderSize32; for (auto *Sec : Sections) { if (Sec->Index == Section::UninitializedIndex || Sec->IsVirtual) continue; diff --git a/llvm/lib/ObjectYAML/XCOFFEmitter.cpp b/llvm/lib/ObjectYAML/XCOFFEmitter.cpp --- a/llvm/lib/ObjectYAML/XCOFFEmitter.cpp +++ b/llvm/lib/ObjectYAML/XCOFFEmitter.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/ADT/DenseMap.h" #include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/MC/StringTableBuilder.h" #include "llvm/Object/XCOFFObjectFile.h" #include "llvm/ObjectYAML/ObjectYAML.h" #include "llvm/ObjectYAML/yaml2obj.h" @@ -29,10 +30,14 @@ class XCOFFWriter { public: XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH) - : Obj(Obj), W(OS, support::big), ErrHandler(EH) {} + : Obj(Obj), W(OS, support::big), ErrHandler(EH), + Strings(StringTableBuilder::XCOFF) { + is64Bit = Obj.Header.Magic == XCOFF::XCOFF64; + } bool writeXCOFF(); private: + bool nameShouldBeInStringTable(StringRef SymbolName); bool initFileHeader(uint64_t CurrentOffset); bool initSectionHeader(uint64_t &CurrentOffset); bool initRelocations(uint64_t &CurrentOffset); @@ -44,8 +49,10 @@ bool writeSymbols(); XCOFFYAML::Object &Obj; + bool is64Bit = false; support::endian::Writer W; yaml::ErrorHandler ErrHandler; + StringTableBuilder Strings; uint64_t StartOffset; // Map the section name to its corrresponding section index. DenseMap SectionIndexMap = { @@ -56,13 +63,19 @@ std::vector InitSections = Obj.Sections; }; +bool XCOFFWriter::nameShouldBeInStringTable(StringRef SymbolName) { + // For XCOFF64: The symbol name is always in string table or .debug section. + return (SymbolName.size() > XCOFF::NameSize) || is64Bit; +} + bool XCOFFWriter::initRelocations(uint64_t &CurrentOffset) { for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { if (!InitSections[I].Relocations.empty()) { InitSections[I].NumberOfRelocations = InitSections[I].Relocations.size(); InitSections[I].FileOffsetToRelocations = CurrentOffset; - CurrentOffset += InitSections[I].NumberOfRelocations * - XCOFF::RelocationSerializationSize32; + uint64_t RelSize = is64Bit ? XCOFF::RelocationSerializationSize64 + : XCOFF::RelocationSerializationSize32; + CurrentOffset += InitSections[I].NumberOfRelocations * RelSize; if (CurrentOffset > MaxRawDataSize) { ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + "exceeded when writing relocation data"); @@ -121,11 +134,16 @@ // The default format of the object file is XCOFF32. InitFileHdr.Magic = XCOFF::XCOFF32; InitFileHdr.NumberOfSections = Obj.Sections.size(); - - // Add the number of auxiliary symbols to the total number. InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); - for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) + + for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { + // Add the number of auxiliary symbols to the total number. InitFileHdr.NumberOfSymTableEntries += YamlSym.NumberOfAuxEntries; + if (nameShouldBeInStringTable(YamlSym.SymbolName)) + Strings.add(YamlSym.SymbolName); + } + // Finalize the string table. + Strings.finalize(); // Calculate SymbolTableOffset for the file header. if (InitFileHdr.NumberOfSymTableEntries) { @@ -143,9 +161,14 @@ } bool XCOFFWriter::assignAddressesAndIndices() { - uint64_t CurrentOffset = - sizeof(XCOFF::FileHeader32) /* TODO: + auxiliaryHeaderSize() */ + - InitSections.size() * sizeof(XCOFF::SectionHeader32); + uint64_t CurrentOffset = 0; + Strings.clear(); + uint64_t FileHdrSize = + is64Bit ? XCOFF::FileHeaderSize64 : XCOFF::FileHeaderSize32; + uint64_t SecHdrSize = + is64Bit ? XCOFF::SectionHeaderSize64 : XCOFF::SectionHeaderSize32; + CurrentOffset = FileHdrSize /* TODO: + auxiliaryHeaderSize() */ + + InitSections.size() * SecHdrSize; // Calculate section header info. if (!initSectionHeader(CurrentOffset)) @@ -159,14 +182,25 @@ W.write(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections : InitFileHdr.NumberOfSections); W.write(Obj.Header.TimeStamp); - W.write(Obj.Header.SymbolTableOffset - ? Obj.Header.SymbolTableOffset - : InitFileHdr.SymbolTableOffset); - W.write(Obj.Header.NumberOfSymTableEntries - ? Obj.Header.NumberOfSymTableEntries - : InitFileHdr.NumberOfSymTableEntries); - W.write(Obj.Header.AuxHeaderSize); - W.write(Obj.Header.Flags); + if (is64Bit) { + W.write(Obj.Header.SymbolTableOffset + ? Obj.Header.SymbolTableOffset + : InitFileHdr.SymbolTableOffset); + W.write(Obj.Header.AuxHeaderSize); + W.write(Obj.Header.Flags); + W.write(Obj.Header.NumberOfSymTableEntries + ? Obj.Header.NumberOfSymTableEntries + : InitFileHdr.NumberOfSymTableEntries); + } else { + W.write(Obj.Header.SymbolTableOffset + ? Obj.Header.SymbolTableOffset + : InitFileHdr.SymbolTableOffset); + W.write(Obj.Header.NumberOfSymTableEntries + ? Obj.Header.NumberOfSymTableEntries + : InitFileHdr.NumberOfSymTableEntries); + W.write(Obj.Header.AuxHeaderSize); + W.write(Obj.Header.Flags); + } } void XCOFFWriter::writeSectionHeader() { @@ -177,22 +211,40 @@ : "N_NULL", sizeof(XCOFF::NameSize)); // Virtual address is the same as physical address. - uint32_t SectionAddress = + uint64_t SectionAddress = YamlSec.Address ? YamlSec.Address : DerivedSec.Address; - W.write(SectionAddress); // Physical address - W.write(SectionAddress); // Virtual address - W.write(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); - W.write(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData - : DerivedSec.FileOffsetToData); - W.write(YamlSec.FileOffsetToRelocations - ? YamlSec.FileOffsetToRelocations - : DerivedSec.FileOffsetToRelocations); - W.write(YamlSec.FileOffsetToLineNumbers); - W.write(YamlSec.NumberOfRelocations - ? YamlSec.NumberOfRelocations - : DerivedSec.NumberOfRelocations); - W.write(YamlSec.NumberOfLineNumbers); - W.write(YamlSec.Flags); + if (is64Bit) { + W.write(SectionAddress); // Physical address + W.write(SectionAddress); // Virtual address + W.write(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); + W.write(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData + : DerivedSec.FileOffsetToData); + W.write(YamlSec.FileOffsetToRelocations + ? YamlSec.FileOffsetToRelocations + : DerivedSec.FileOffsetToRelocations); + W.write(YamlSec.FileOffsetToLineNumbers); + W.write(YamlSec.NumberOfRelocations + ? YamlSec.NumberOfRelocations + : DerivedSec.NumberOfRelocations); + W.write(YamlSec.NumberOfLineNumbers); + W.write(YamlSec.Flags); + W.OS.write_zeros(4); + } else { + W.write(SectionAddress); // Physical address + W.write(SectionAddress); // Virtual address + W.write(YamlSec.Size ? YamlSec.Size : DerivedSec.Size); + W.write(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData + : DerivedSec.FileOffsetToData); + W.write(YamlSec.FileOffsetToRelocations + ? YamlSec.FileOffsetToRelocations + : DerivedSec.FileOffsetToRelocations); + W.write(YamlSec.FileOffsetToLineNumbers); + W.write(YamlSec.NumberOfRelocations + ? YamlSec.NumberOfRelocations + : DerivedSec.NumberOfRelocations); + W.write(YamlSec.NumberOfLineNumbers); + W.write(YamlSec.Flags); + } } } @@ -226,7 +278,10 @@ } W.OS.write_zeros(PaddingSize); for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { - W.write(YamlRel.VirtualAddress); + if (is64Bit) + W.write(YamlRel.VirtualAddress); + else + W.write(YamlRel.VirtualAddress); W.write(YamlRel.SymbolIndex); W.write(YamlRel.Info); W.write(YamlRel.Type); @@ -245,12 +300,19 @@ } W.OS.write_zeros(PaddingSize); for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { - if (YamlSym.SymbolName.size() > XCOFF::NameSize) { - ErrHandler("string table is not supported yet"); - return false; + if (nameShouldBeInStringTable(YamlSym.SymbolName)) { + // For XCOFF32: A value of 0 indicates that the symbol name is in the + // string table or .debug section. + if (!is64Bit) + W.write(0); + W.write(Strings.getOffset(YamlSym.SymbolName)); + } else { + W.OS.write(YamlSym.SymbolName.data(), sizeof(XCOFF::NameSize)); } - W.OS.write(YamlSym.SymbolName.data(), sizeof(XCOFF::NameSize)); - W.write(YamlSym.Value); + if (is64Bit) + W.write(YamlSym.Value); + else + W.write(YamlSym.Value); W.write(SectionIndexMap[YamlSym.SectionName]); W.write(YamlSym.Type); W.write(YamlSym.StorageClass); @@ -281,9 +343,12 @@ if (!writeRelocations()) return false; } - if (!Obj.Symbols.empty()) - return writeSymbols(); - // TODO: Add support for the string table. + if (!Obj.Symbols.empty()) { + if (!writeSymbols()) + return false; + // Write the string table. + Strings.write(W.OS); + } return true; } @@ -293,11 +358,6 @@ namespace yaml { bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) { - bool Is64Bit = Doc.Header.Magic == XCOFF::XCOFF64; - if (Is64Bit) { - EH("only XCOFF32 is supported now"); - return false; - } XCOFFWriter Writer(Doc, Out, EH); return Writer.writeXCOFF(); } diff --git a/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml b/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml --- a/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml +++ b/llvm/test/tools/yaml2obj/XCOFF/basic-doc64.yaml @@ -0,0 +1,117 @@ +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj --headers %t | FileCheck %s --check-prefix=HEADERS64 +# RUN: llvm-readobj --symbols %t | FileCheck %s --check-prefix=SYMBOLS64 + +--- !XCOFF +FileHeader: + MagicNumber: 0x01F7 +Sections: + - Name: .text + Flags: 0x20 + SectionData: "9061FFF8808200008064000038630001906400008061FFF8386300019061FFF88061FFF88082000480840000888400007C6322149061FFF88061FFF84E8000200000000000092040800001010000000000000040000466756E310000600000007C0802A693E1FFFC900100089421FFB07C3F0B7838600000907F004880620008907F0044808300003884000190830000806300004BFFFF6D60000000807F0044806300004BFFFF5D60000000382100508001000883E1FFFC7C0803A64E8000200000000000092261800100010000006000046D61696E1F006162636400000000" + - Name: .data + Flags: 0x40 + SectionData: "00000000000000FC0000000000000060000000FC00000000000000D800000108000000F800000000" + Relocations: + - Address: 0x3A + Type: 0x02 + - Flags: 0x80 +Symbols: + - Name: .file + Section: N_DEBUG + - Name: .text + Value: 0x0 + Section: .text + Type: 0x0 + StorageClass: C_HIDEXT + - Name: i + Value: 0x0 + Section: .data + Type: 0x0 + StorageClass: C_EXT + + +# HEADERS64: Format: aix5coff64-rs6000 +# HEADERS64-NEXT: Arch: powerpc64 +# HEADERS64-NEXT: AddressSize: 64bit +# HEADERS64-NEXT: FileHeader { +# HEADERS64-NEXT: Magic: 0x1F7 +# HEADERS64-NEXT: NumberOfSections: 3 +# HEADERS64-NEXT: TimeStamp: None (0x0) +# HEADERS64-NEXT: SymbolTableOffset: 0x206 +# HEADERS64-NEXT: SymbolTableEntries: 3 +# HEADERS64-NEXT: OptionalHeaderSize: 0x0 +# HEADERS64-NEXT: Flags: 0x0 +# HEADERS64-NEXT: } + +# HEADERS64: Sections [ +# HEADERS64-NEXT: Section { +# HEADERS64-NEXT: Index: 1 +# HEADERS64-NEXT: Name: .text +# HEADERS64: PhysicalAddress: 0x0 +# HEADERS64-NEXT: VirtualAddress: 0x0 +# HEADERS64-NEXT: Size: 0xE0 +# HEADERS64-NEXT: RawDataOffset: 0xF0 +# HEADERS64-NEXT: RelocationPointer: 0x0 +# HEADERS64-NEXT: LineNumberPointer: 0x0 +# HEADERS64-NEXT: NumberOfRelocations: 0 +# HEADERS64-NEXT: NumberOfLineNumbers: 0 +# HEADERS64-NEXT: Type: STYP_TEXT (0x20) +# HEADERS64-NEXT: } +# HEADERS64-NEXT: Section { +# HEADERS64-NEXT: Index: 2 +# HEADERS64-NEXT: Name: .data +# HEADERS64: PhysicalAddress: 0xE0 +# HEADERS64-NEXT: VirtualAddress: 0xE0 +# HEADERS64-NEXT: Size: 0x28 +# HEADERS64-NEXT: RawDataOffset: 0x1D0 +# HEADERS64-NEXT: RelocationPointer: 0x1F8 +# HEADERS64-NEXT: LineNumberPointer: 0x0 +# HEADERS64-NEXT: NumberOfRelocations: 1 +# HEADERS64-NEXT: NumberOfLineNumbers: 0 +# HEADERS64-NEXT: Type: STYP_DATA (0x40) +# HEADERS64-NEXT: } +# HEADERS64-NEXT: Section { +# HEADERS64-NEXT: Index: 3 +# HEADERS64-NEXT: Name: N_NULL +# HEADERS64-NEXT: PhysicalAddress: 0x108 +# HEADERS64-NEXT: VirtualAddress: 0x108 +# HEADERS64-NEXT: Size: 0x0 +# HEADERS64-NEXT: RawDataOffset: 0x0 +# HEADERS64-NEXT: RelocationPointer: 0x0 +# HEADERS64-NEXT: LineNumberPointer: 0x0 +# HEADERS64-NEXT: NumberOfRelocations: 0 +# HEADERS64-NEXT: NumberOfLineNumbers: 0 +# HEADERS64-NEXT: Type: STYP_BSS (0x80) +# HEADERS64-NEXT: } +# HEADERS64-NEXT: ] + +#SYMBOLS64: Symbols [ +#SYMBOLS64-NEXT: Symbol { +#SYMBOLS64-NEXT: Index: 0 +#SYMBOLS64-NEXT: Name: +#SYMBOLS64-NEXT: Value: 0xC00000000 +#SYMBOLS64-NEXT: Section: N_DEBUG +#SYMBOLS64-NEXT: Type: 0x0 +#SYMBOLS64-NEXT: StorageClass: C_NULL (0x0) +#SYMBOLS64-NEXT: NumberOfAuxEntries: 0 +#SYMBOLS64-NEXT: } +#SYMBOLS64-NEXT: Symbol { +#SYMBOLS64-NEXT: Index: 1 +#SYMBOLS64-NEXT: Name: +#SYMBOLS64-NEXT: Value (RelocatableAddress): 0x400000000 +#SYMBOLS64-NEXT: Section: .text +#SYMBOLS64: Type: 0x0 +#SYMBOLS64-NEXT: StorageClass: C_HIDEXT (0x6B) +#SYMBOLS64-NEXT: NumberOfAuxEntries: 0 +#SYMBOLS64-NEXT: } +#SYMBOLS64-NEXT: Symbol { +#SYMBOLS64-NEXT: Index: 2 +#SYMBOLS64-NEXT: Name: +#SYMBOLS64-NEXT: Value (RelocatableAddress): 0xA00000000 +#SYMBOLS64-NEXT: Section: .data +#SYMBOLS64: Type: 0x0 +#SYMBOLS64-NEXT: StorageClass: C_EXT (0x2) +#SYMBOLS64-NEXT: NumberOfAuxEntries: 0 +#SYMBOLS64-NEXT: } +#SYMBOLS64-NEXT: ]