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 @@ -33,6 +33,8 @@ enum ReservedSectionNum : int16_t { N_DEBUG = -2, N_ABS = -1, N_UNDEF = 0 }; +enum MagicNumber : uint16_t { XCOFF32 = 0x01DF, XCOFF64 = 0x01F7 }; + // x_smclas field of x_csect from system header: /usr/include/syms.h /// Storage Mapping Class definitions. enum StorageMappingClass : uint8_t { diff --git a/llvm/include/llvm/ObjectYAML/ObjectYAML.h b/llvm/include/llvm/ObjectYAML/ObjectYAML.h --- a/llvm/include/llvm/ObjectYAML/ObjectYAML.h +++ b/llvm/include/llvm/ObjectYAML/ObjectYAML.h @@ -15,6 +15,7 @@ #include "llvm/ObjectYAML/MachOYAML.h" #include "llvm/ObjectYAML/MinidumpYAML.h" #include "llvm/ObjectYAML/WasmYAML.h" +#include "llvm/ObjectYAML/XCOFFYAML.h" #include "llvm/Support/YAMLTraits.h" #include @@ -31,6 +32,7 @@ std::unique_ptr FatMachO; std::unique_ptr Minidump; std::unique_ptr Wasm; + std::unique_ptr Xcoff; }; template <> struct MappingTraits { diff --git a/llvm/include/llvm/ObjectYAML/XCOFFYAML.h b/llvm/include/llvm/ObjectYAML/XCOFFYAML.h --- a/llvm/include/llvm/ObjectYAML/XCOFFYAML.h +++ b/llvm/include/llvm/ObjectYAML/XCOFFYAML.h @@ -23,32 +23,62 @@ llvm::yaml::Hex16 Magic; uint16_t NumberOfSections; int32_t TimeStamp; - llvm::yaml::Hex32 SymbolTableOffset; // File offset to symbol table. - int32_t NumberOfSymTableEntries; + llvm::yaml::Hex64 SymbolTableOffset; + uint32_t NumberOfSymTableEntries; uint16_t AuxHeaderSize; llvm::yaml::Hex16 Flags; }; +struct Relocation { + llvm::yaml::Hex64 VirtualAddress; + llvm::yaml::Hex64 SymbolIndex; + llvm::yaml::Hex8 Info; + llvm::yaml::Hex8 Type; +}; + +struct Section { + StringRef SectionName; + llvm::yaml::Hex64 Address; + llvm::yaml::Hex64 Size; + llvm::yaml::Hex64 FileOffsetToData; + llvm::yaml::Hex64 FileOffsetToRelocations; + llvm::yaml::Hex64 FileOffsetToLineNumbers; // Line number pointer. Not supported yet. + llvm::yaml::Hex16 NumberOfRelocations; + llvm::yaml::Hex16 NumberOfLineNumbers; // Line number counts. Not supported yet. + uint32_t Flags; + yaml::BinaryRef SectionData; + std::vector Relocations; +}; + struct Symbol { StringRef SymbolName; - llvm::yaml::Hex32 Value; // Symbol value; storage class-dependent. + llvm::yaml::Hex64 Value; // Symbol value; storage class-dependent. StringRef SectionName; llvm::yaml::Hex16 Type; XCOFF::StorageClass StorageClass; - uint8_t NumberOfAuxEntries; // Number of auxiliary entries + uint8_t NumberOfAuxEntries; }; struct Object { FileHeader Header; + std::vector
Sections; std::vector Symbols; Object(); }; } // namespace XCOFFYAML } // namespace llvm + LLVM_YAML_IS_SEQUENCE_VECTOR(XCOFFYAML::Symbol) +LLVM_YAML_IS_SEQUENCE_VECTOR(XCOFFYAML::Relocation) +LLVM_YAML_IS_SEQUENCE_VECTOR(XCOFFYAML::Section) + namespace llvm { namespace yaml { +template <> struct ScalarBitSetTraits { + static void bitset(IO &IO, XCOFF::SectionTypeFlags &Value); +}; + template <> struct ScalarEnumerationTraits { static void enumeration(IO &IO, XCOFF::StorageClass &Value); }; @@ -57,14 +87,23 @@ static void mapping(IO &IO, XCOFFYAML::FileHeader &H); }; -template <> struct MappingTraits { - static void mapping(IO &IO, XCOFFYAML::Object &Obj); -}; template <> struct MappingTraits { static void mapping(IO &IO, XCOFFYAML::Symbol &S); }; +template <> struct MappingTraits { + static void mapping(IO &IO, XCOFFYAML::Relocation &R); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, XCOFFYAML::Section &Sec); +}; + +template <> struct MappingTraits { + static void mapping(IO &IO, XCOFFYAML::Object &Obj); +}; + } // namespace yaml } // namespace llvm diff --git a/llvm/include/llvm/ObjectYAML/yaml2obj.h b/llvm/include/llvm/ObjectYAML/yaml2obj.h --- a/llvm/include/llvm/ObjectYAML/yaml2obj.h +++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h @@ -40,6 +40,10 @@ struct Object; } +namespace XCOFFYAML { +struct Object; +} + namespace ArchYAML { struct Archive; } @@ -58,6 +62,7 @@ bool yaml2minidump(MinidumpYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH); bool yaml2wasm(WasmYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH); +bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH); bool convertYAML(Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler, unsigned DocNum = 1, uint64_t MaxSize = UINT64_MAX); diff --git a/llvm/lib/ObjectYAML/CMakeLists.txt b/llvm/lib/ObjectYAML/CMakeLists.txt --- a/llvm/lib/ObjectYAML/CMakeLists.txt +++ b/llvm/lib/ObjectYAML/CMakeLists.txt @@ -18,6 +18,7 @@ MinidumpYAML.cpp WasmEmitter.cpp WasmYAML.cpp + XCOFFEmitter.cpp XCOFFYAML.cpp YAML.cpp yaml2obj.cpp diff --git a/llvm/lib/ObjectYAML/ObjectYAML.cpp b/llvm/lib/ObjectYAML/ObjectYAML.cpp --- a/llvm/lib/ObjectYAML/ObjectYAML.cpp +++ b/llvm/lib/ObjectYAML/ObjectYAML.cpp @@ -59,6 +59,9 @@ } else if (IO.mapTag("!WASM")) { ObjectFile.Wasm.reset(new WasmYAML::Object()); MappingTraits::mapping(IO, *ObjectFile.Wasm); + } else if (IO.mapTag("!XCOFF")) { + ObjectFile.Xcoff.reset(new XCOFFYAML::Object()); + MappingTraits::mapping(IO, *ObjectFile.Xcoff); } else if (const Node *N = In.getCurrentNode()) { if (N->getRawTag().empty()) IO.setError("YAML Object File missing document type tag!"); diff --git a/llvm/lib/ObjectYAML/XCOFFEmitter.cpp b/llvm/lib/ObjectYAML/XCOFFEmitter.cpp new file mode 100644 --- /dev/null +++ b/llvm/lib/ObjectYAML/XCOFFEmitter.cpp @@ -0,0 +1,315 @@ +//===- yaml2xcoff - Convert YAML to a xcoff object file -------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// The xcoff component of yaml2obj. +/// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/DenseMap.h" +#include "llvm/BinaryFormat/XCOFF.h" +#include "llvm/Object/XCOFFObjectFile.h" +#include "llvm/ObjectYAML/ObjectYAML.h" +#include "llvm/ObjectYAML/yaml2obj.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/Support/LEB128.h" + +using namespace llvm; + +namespace { + +constexpr unsigned DefaultSectionAlign = 4; +constexpr int16_t MaxSectionIndex = INT16_MAX; +constexpr uint32_t MaxRawDataSize = UINT32_MAX; + +class XCOFFWriter { +public: + XCOFFWriter(XCOFFYAML::Object &Obj, raw_ostream &OS, yaml::ErrorHandler EH) + : Obj(Obj), W(OS, support::big), ErrHandler(EH) { + Is64Bit = Obj.Header.Magic == XCOFF::XCOFF64; + } + bool writeXCOFF(); + +private: + bool initFileHeader(uint64_t CurrentOffset); + bool initSectionHeader(uint64_t &CurrentOffset); + bool initRelocations(uint64_t &CurrentOffset); + bool assignAddressesAndIndices(); + void writeFileHeader(); + void writeSectionHeader(); + bool writeSectionData(); + bool writeRelocations(); + bool writeSymbols(); + + XCOFFYAML::Object &Obj; + bool Is64Bit = false; + support::endian::Writer W; + yaml::ErrorHandler ErrHandler; + uint64_t StartOffset; + // Map the section name to its corrresponding section index. + DenseMap SectionIndexMap = { + {StringRef("N_DEBUG"), XCOFF::N_DEBUG}, + {StringRef("N_ABS"), XCOFF::N_ABS}, + {StringRef("N_UNDEF"), XCOFF::N_UNDEF}}; + XCOFFYAML::FileHeader InitFileHdr = Obj.Header; + std::vector InitSections = Obj.Sections; +}; + +static void writeName(StringRef StrName, support::endian::Writer W) { + char Name[XCOFF::NameSize]; + memset(Name, 0, XCOFF::NameSize); + memcpy(Name, StrName.data(), StrName.size()); + ArrayRef NameRef(Name, XCOFF::NameSize); + W.write(NameRef); +} + +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; + if (CurrentOffset > MaxRawDataSize) { + ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + + "exceeded when writing relocation data"); + return false; + } + } + } + return true; +} + +bool XCOFFWriter::initSectionHeader(uint64_t &CurrentOffset) { + uint64_t CurrentSecAddr = 0; + for (uint16_t I = 0, E = InitSections.size(); I < E; ++I) { + if (CurrentOffset > MaxRawDataSize) { + ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + + "exceeded when writing section data"); + return false; + } + + // Assign indices for sections. + if (InitSections[I].SectionName.size() && + !SectionIndexMap[InitSections[I].SectionName]) { + // The section index starts from 1. + SectionIndexMap[InitSections[I].SectionName] = I + 1; + if ((I + 1) > MaxSectionIndex) { + ErrHandler("exceeded the maximum permitted section index of " + + Twine(MaxSectionIndex)); + return false; + } + } + + // Calculate the physical/virtual address. This field should contain 0 for + // all sections except the text, data and bss sections. + if (InitSections[I].Flags != XCOFF::STYP_TEXT && + InitSections[I].Flags != XCOFF::STYP_DATA && + InitSections[I].Flags != XCOFF::STYP_BSS) + InitSections[I].Address = 0; + else + InitSections[I].Address = CurrentSecAddr; + + // Calculate the FileOffsetToData and data size for sections. + if (InitSections[I].SectionData.binary_size()) { + InitSections[I].FileOffsetToData = CurrentOffset; + CurrentOffset += InitSections[I].SectionData.binary_size(); + // Ensure the offset is aligned to DefaultSectionAlign. + CurrentOffset = alignTo(CurrentOffset, DefaultSectionAlign); + InitSections[I].Size = CurrentOffset - InitSections[I].FileOffsetToData; + CurrentSecAddr += InitSections[I].Size; + } + } + return initRelocations(CurrentOffset); +} + +bool XCOFFWriter::initFileHeader(uint64_t CurrentOffset) { + // The default format of the object file is XCOFF32. + InitFileHdr.Magic = XCOFF::XCOFF32; + InitFileHdr.NumberOfSections = Obj.Sections.size(); + InitFileHdr.NumberOfSymTableEntries = Obj.Symbols.size(); + + for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { + // Add the number of auxiliary symbols to the total number. + InitFileHdr.NumberOfSymTableEntries += YamlSym.NumberOfAuxEntries; + } + + // Calculate SymbolTableOffset for the file header. + if (InitFileHdr.NumberOfSymTableEntries) { + InitFileHdr.SymbolTableOffset = CurrentOffset; + CurrentOffset += + InitFileHdr.NumberOfSymTableEntries * XCOFF::SymbolTableEntrySize; + if (CurrentOffset > MaxRawDataSize) { + ErrHandler("maximum object size of" + Twine(MaxRawDataSize) + + "exceeded when writing symbols"); + return false; + } + } + // TODO: Calculate FileOffsetToLineNumbers when line number supported. + return true; +} + +bool XCOFFWriter::assignAddressesAndIndices() { + uint64_t CurrentOffset = + sizeof(XCOFF::FileHeader32) /* TODO: + auxiliaryHeaderSize() */ + + InitSections.size() * sizeof(XCOFF::SectionHeader32); + + // Calculate section header info. + if (!initSectionHeader(CurrentOffset)) + return false; + // Calculate file header info. + return initFileHeader(CurrentOffset); +} + +void XCOFFWriter::writeFileHeader() { + W.write(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic); + 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); +} + +void XCOFFWriter::writeSectionHeader() { + for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { + XCOFFYAML::Section YamlSec = Obj.Sections[I]; + XCOFFYAML::Section DerivedSec = InitSections[I]; + writeName(YamlSec.SectionName, W); + // Virtual address is the same as physical address. + uint32_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); + } +} + +bool XCOFFWriter::writeSectionData() { + for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { + XCOFFYAML::Section YamlSec = Obj.Sections[I]; + if (YamlSec.SectionData.binary_size()) { + // Fill the padding size with zeros. + int64_t PaddingSize = + InitSections[I].FileOffsetToData - (W.OS.tell() - StartOffset); + if (PaddingSize < 0) { + ErrHandler("redundant data was written before section data"); + return false; + } + if (PaddingSize > 0) + W.OS.write_zeros(PaddingSize); + YamlSec.SectionData.writeAsBinary(W.OS); + } + } + return true; +} + +bool XCOFFWriter::writeRelocations() { + for (uint16_t I = 0, E = Obj.Sections.size(); I < E; ++I) { + XCOFFYAML::Section YamlSec = Obj.Sections[I]; + if (!YamlSec.Relocations.empty()) { + int64_t PaddingSize = + InitSections[I].FileOffsetToRelocations - (W.OS.tell() - StartOffset); + if (PaddingSize < 0) { + ErrHandler("redundant data was written before relocations"); + return false; + } + if (PaddingSize > 0) + W.OS.write_zeros(PaddingSize); + for (const XCOFFYAML::Relocation &YamlRel : YamlSec.Relocations) { + W.write(YamlRel.VirtualAddress); + W.write(YamlRel.SymbolIndex); + W.write(YamlRel.Info); + W.write(YamlRel.Type); + } + } + } + return true; +} + +bool XCOFFWriter::writeSymbols() { + int64_t PaddingSize = + (uint64_t)InitFileHdr.SymbolTableOffset - (W.OS.tell() - StartOffset); + if (PaddingSize < 0) { + ErrHandler("redundant data was written before symbols"); + return false; + } + if (PaddingSize > 0) + W.OS.write_zeros(PaddingSize); + for (const XCOFFYAML::Symbol &YamlSym : Obj.Symbols) { + writeName(YamlSym.SymbolName, W); + W.write(YamlSym.Value); + W.write( + YamlSym.SectionName.size() ? SectionIndexMap[YamlSym.SectionName] : 0); + W.write(YamlSym.Type); + W.write(YamlSym.StorageClass); + W.write(YamlSym.NumberOfAuxEntries); + + // Now output the auxiliary entry. + for (uint8_t I = 0, E = YamlSym.NumberOfAuxEntries; I < E; ++I) { + // TODO: Auxiliary entry is not supported yet. + // The auxiliary entries for a symbol follow its symbol table entry. The + // length of each auxiliary entry is the same as a symbol table entry (18 + // bytes). The format and quantity of auxiliary entries depend on the + // storage class (n_sclass) and type (n_type) of the symbol table entry. + W.OS.write_zeros(18); + } + } + return true; +} + +bool XCOFFWriter::writeXCOFF() { + if (Is64Bit) { + ErrHandler("only XCOFF32 is currently supported"); + return false; + } + if (!assignAddressesAndIndices()) + return false; + StartOffset = W.OS.tell(); + writeFileHeader(); + if (!Obj.Sections.empty()) { + writeSectionHeader(); + if (!writeSectionData()) + return false; + if (!writeRelocations()) + return false; + } + if (!Obj.Symbols.empty()) + return writeSymbols(); + return true; +} + +} // end anonymous namespace + +namespace llvm { +namespace yaml { + +bool yaml2xcoff(XCOFFYAML::Object &Doc, raw_ostream &Out, ErrorHandler EH) { + XCOFFWriter Writer(Doc, Out, EH); + return Writer.writeXCOFF(); +} + +} // namespace yaml +} // namespace llvm diff --git a/llvm/lib/ObjectYAML/XCOFFYAML.cpp b/llvm/lib/ObjectYAML/XCOFFYAML.cpp --- a/llvm/lib/ObjectYAML/XCOFFYAML.cpp +++ b/llvm/lib/ObjectYAML/XCOFFYAML.cpp @@ -23,6 +23,25 @@ namespace yaml { +void ScalarBitSetTraits::bitset( + IO &IO, XCOFF::SectionTypeFlags &Value) { +#define ECase(X) IO.bitSetCase(Value, #X, XCOFF::X) + ECase(STYP_PAD); + ECase(STYP_DWARF); + ECase(STYP_TEXT); + ECase(STYP_DATA); + ECase(STYP_BSS); + ECase(STYP_EXCEPT); + ECase(STYP_INFO); + ECase(STYP_TDATA); + ECase(STYP_TBSS); + ECase(STYP_LOADER); + ECase(STYP_DEBUG); + ECase(STYP_TYPCHK); + ECase(STYP_OVRFLO); +#undef ECase +} + void ScalarEnumerationTraits::enumeration( IO &IO, XCOFF::StorageClass &Value) { #define ECase(X) IO.enumCase(Value, #X, XCOFF::X) @@ -79,30 +98,64 @@ #undef ECase } +struct NSectionFlags { + NSectionFlags(IO &) : Flags(XCOFF::SectionTypeFlags(0)) {} + NSectionFlags(IO &, uint32_t C) : Flags(XCOFF::SectionTypeFlags(C)) {} + + uint32_t denormalize(IO &) { return Flags; } + + XCOFF::SectionTypeFlags Flags; +}; + void MappingTraits::mapping( IO &IO, XCOFFYAML::FileHeader &FileHdr) { - IO.mapRequired("MagicNumber", FileHdr.Magic); - IO.mapRequired("NumberOfSections", FileHdr.NumberOfSections); - IO.mapRequired("CreationTime", FileHdr.TimeStamp); - IO.mapRequired("OffsetToSymbolTable", FileHdr.SymbolTableOffset); - IO.mapRequired("EntriesInSymbolTable", FileHdr.NumberOfSymTableEntries); - IO.mapRequired("AuxiliaryHeaderSize", FileHdr.AuxHeaderSize); - IO.mapRequired("Flags", FileHdr.Flags); + IO.mapOptional("MagicNumber", FileHdr.Magic); + IO.mapOptional("NumberOfSections", FileHdr.NumberOfSections); + IO.mapOptional("CreationTime", FileHdr.TimeStamp); + IO.mapOptional("OffsetToSymbolTable", FileHdr.SymbolTableOffset); + IO.mapOptional("EntriesInSymbolTable", FileHdr.NumberOfSymTableEntries); + IO.mapOptional("AuxiliaryHeaderSize", FileHdr.AuxHeaderSize); + IO.mapOptional("Flags", FileHdr.Flags); +} + +void MappingTraits::mapping(IO &IO, + XCOFFYAML::Relocation &R) { + IO.mapOptional("Address", R.VirtualAddress); + IO.mapOptional("Symbol", R.SymbolIndex); + IO.mapOptional("Info", R.Info); + IO.mapOptional("Type", R.Type); +} + +void MappingTraits::mapping(IO &IO, + XCOFFYAML::Section &Sec) { + MappingNormalization NC(IO, Sec.Flags); + IO.mapOptional("Name", Sec.SectionName); + IO.mapOptional("Address", Sec.Address); + IO.mapOptional("Size", Sec.Size); + IO.mapOptional("FileOffsetToData", Sec.FileOffsetToData); + IO.mapOptional("FileOffsetToRelocations", Sec.FileOffsetToRelocations); + IO.mapOptional("FileOffsetToLineNumbers", Sec.FileOffsetToLineNumbers); + IO.mapOptional("NumberOfRelocations", Sec.NumberOfRelocations); + IO.mapOptional("NumberOfLineNumbers", Sec.NumberOfLineNumbers); + IO.mapOptional("Flags", NC->Flags); + IO.mapOptional("SectionData", Sec.SectionData); + IO.mapOptional("Relocations", Sec.Relocations); } void MappingTraits::mapping(IO &IO, XCOFFYAML::Symbol &S) { IO.mapRequired("Name", S.SymbolName); - IO.mapRequired("Value", S.Value); - IO.mapRequired("Section", S.SectionName); - IO.mapRequired("Type", S.Type); - IO.mapRequired("StorageClass", S.StorageClass); - IO.mapRequired("NumberOfAuxEntries", S.NumberOfAuxEntries); + IO.mapOptional("Value", S.Value); + IO.mapOptional("Section", S.SectionName); + IO.mapOptional("Type", S.Type); + IO.mapOptional("StorageClass", S.StorageClass); + IO.mapOptional("NumberOfAuxEntries", S.NumberOfAuxEntries); } void MappingTraits::mapping(IO &IO, XCOFFYAML::Object &Obj) { IO.mapTag("!XCOFF", true); IO.mapRequired("FileHeader", Obj.Header); - IO.mapRequired("Symbols", Obj.Symbols); + IO.mapOptional("Sections", Obj.Sections); + IO.mapOptional("Symbols", Obj.Symbols); } } // namespace yaml diff --git a/llvm/lib/ObjectYAML/yaml2obj.cpp b/llvm/lib/ObjectYAML/yaml2obj.cpp --- a/llvm/lib/ObjectYAML/yaml2obj.cpp +++ b/llvm/lib/ObjectYAML/yaml2obj.cpp @@ -44,6 +44,8 @@ return yaml2minidump(*Doc.Minidump, Out, ErrHandler); if (Doc.Wasm) return yaml2wasm(*Doc.Wasm, Out, ErrHandler); + if (Doc.Xcoff) + return yaml2xcoff(*Doc.Xcoff, Out, ErrHandler); ErrHandler("unknown document type"); return false; diff --git a/llvm/test/tools/yaml2obj/XCOFF/basic-doc.yaml b/llvm/test/tools/yaml2obj/XCOFF/basic-doc.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/XCOFF/basic-doc.yaml @@ -0,0 +1,164 @@ +## Check that yaml2obj automatically assigns omited fields with values. +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj --headers --symbols %t | FileCheck %s + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF +Sections: + - Name: .text + Flags: [ STYP_TEXT ] + SectionData: "9061FFF880820000" + - Name: .data + Flags: [ STYP_DATA ] + SectionData: "0000000000000FC0" + Relocations: + - Address: 0x08 + - Name: .data + Relocations: + - Type: 0x02 + - Name: .debug + Address: 0x0 + Size: 0x60 + Flags: [ STYP_DEBUG, STYP_DATA ] + SectionData: 01110103 + - Flags: [ STYP_BSS, STYP_DWARF, STYP_EXCEPT, STYP_INFO, STYP_TDATA, STYP_TBSS, STYP_LOADER, STYP_TYPCHK, STYP_OVRFLO ] +Symbols: + - Name: .file + Section: N_DEBUG + - Name: .undef + - Name: .abs + Section: N_ABS + - Name: .text + Value: 0x0 + Section: .text + Type: 0x0 + StorageClass: C_HIDEXT + NumberOfAuxEntries: 1 + +# CHECK: AddressSize: 32bit +# CHECK-NEXT: FileHeader { +# CHECK-NEXT: Magic: 0x1DF +# CHECK-NEXT: NumberOfSections: 5 +# CHECK-NEXT: TimeStamp: None (0x0) +# CHECK-NEXT: SymbolTableOffset: 0x104 +# CHECK-NEXT: SymbolTableEntries: 5 +# CHECK-NEXT: OptionalHeaderSize: 0x0 +# CHECK-NEXT: Flags: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Sections [ +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: Size: 0x8 +# CHECK-NEXT: RawDataOffset: 0xDC +# CHECK-NEXT: RelocationPointer: 0x0 +# CHECK-NEXT: LineNumberPointer: 0x0 +# CHECK-NEXT: NumberOfRelocations: 0 +# CHECK-NEXT: NumberOfLineNumbers: 0 +# CHECK-NEXT: Type: STYP_TEXT (0x20) +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .data +# CHECK-NEXT: PhysicalAddress: 0x8 +# CHECK-NEXT: VirtualAddress: 0x8 +# CHECK-NEXT: Size: 0x8 +# CHECK-NEXT: RawDataOffset: 0xE4 +# CHECK-NEXT: RelocationPointer: 0xF0 +# CHECK-NEXT: LineNumberPointer: 0x0 +# CHECK-NEXT: NumberOfRelocations: 1 +# CHECK-NEXT: NumberOfLineNumbers: 0 +# CHECK-NEXT: Type: STYP_DATA (0x40) +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .data +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: Size: 0x0 +# CHECK-NEXT: RawDataOffset: 0x0 +# CHECK-NEXT: RelocationPointer: 0xFA +# CHECK-NEXT: LineNumberPointer: 0x0 +# CHECK-NEXT: NumberOfRelocations: 1 +# CHECK-NEXT: NumberOfLineNumbers: 0 +# CHECK-NEXT: Type: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: Name: .debug +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: Size: 0x60 +# CHECK-NEXT: RawDataOffset: 0xEC +# CHECK-NEXT: RelocationPointer: 0x0 +# CHECK-NEXT: LineNumberPointer: 0x0 +# CHECK-NEXT: NumberOfRelocations: 0 +# CHECK-NEXT: NumberOfLineNumbers: 0 +# CHECK-NEXT: Type: 0x2040 +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 5 +# CHECK-NEXT: Name: +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: Size: 0x0 +# CHECK-NEXT: RawDataOffset: 0x0 +# CHECK-NEXT: RelocationPointer: 0x0 +# CHECK-NEXT: LineNumberPointer: 0x0 +# CHECK-NEXT: NumberOfRelocations: 0 +# CHECK-NEXT: NumberOfLineNumbers: 0 +# CHECK-NEXT: Type: 0xDF90 +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: .file +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Section: N_DEBUG +# CHECK-NEXT: Type: 0x0 +# CHECK-NEXT: StorageClass: C_NULL (0x0) +# CHECK-NEXT: NumberOfAuxEntries: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: .undef +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Section: N_UNDEF +# CHECK-NEXT: Type: 0x0 +# CHECK-NEXT: StorageClass: C_NULL (0x0) +# CHECK-NEXT: NumberOfAuxEntries: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .abs +# CHECK-NEXT: Value: 0x0 +# CHECK-NEXT: Section: N_ABS +# CHECK-NEXT: Type: 0x0 +# CHECK-NEXT: StorageClass: C_NULL (0x0) +# CHECK-NEXT: NumberOfAuxEntries: 0 +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Value (RelocatableAddress): 0x0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: Type: 0x0 +# CHECK-NEXT: StorageClass: C_HIDEXT (0x6B) +# CHECK-NEXT: NumberOfAuxEntries: 1 +# CHECK-NEXT: CSECT Auxiliary Entry { +# CHECK-NEXT: Index: 4 +# CHECK-NEXT: SectionLen: 0 +# CHECK-NEXT: ParameterHashIndex: 0x0 +# CHECK-NEXT: TypeChkSectNum: 0x0 +# CHECK-NEXT: SymbolAlignmentLog2: 0 +# CHECK-NEXT: SymbolType: XTY_ER (0x0) +# CHECK-NEXT: StorageMappingClass: XMC_PR (0x0) +# CHECK-NEXT: StabInfoIndex: 0x0 +# CHECK-NEXT: StabSectNum: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] diff --git a/llvm/test/tools/yaml2obj/XCOFF/full-contents.yaml b/llvm/test/tools/yaml2obj/XCOFF/full-contents.yaml new file mode 100644 --- /dev/null +++ b/llvm/test/tools/yaml2obj/XCOFF/full-contents.yaml @@ -0,0 +1,122 @@ +## Test that we can explicitly specify all the fields. +# RUN: yaml2obj %s -o %t +# RUN: llvm-readobj --headers --symbols %t | FileCheck %s + +--- !XCOFF +FileHeader: + MagicNumber: 0x1DF + NumberOfSections: 2 + CreationTime: 0 + OffsetToSymbolTable: 0x7A + EntriesInSymbolTable: 4 + AuxiliaryHeaderSize: 0 + Flags: 0x0 +Sections: + - Name: .text + Address: 0x0 + Size: 0x8 + FileOffsetToData: 0x64 + FileOffsetToRelocations: 0x0 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x0 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_TEXT ] + SectionData: "3860000048" + - Name: .data + Address: 0x8 + Size: 0x4 + FileOffsetToData: 0x6C + FileOffsetToRelocations: 0x70 + FileOffsetToLineNumbers: 0x0 + NumberOfRelocations: 0x1 + NumberOfLineNumbers: 0x0 + Flags: [ STYP_DATA ] + SectionData: "00000088" + Relocations: + - Address: 0x80 + Symbol: 0x21 + Info: 0x1F + Type: 0x0 +Symbols: + - Name: .text + Value: 0x0 + Section: .text + Type: 0x0 + StorageClass: C_STAT + NumberOfAuxEntries: 1 + - Name: .data + Value: 0x80 + Section: .data + Type: 0x0 + StorageClass: C_STAT + NumberOfAuxEntries: 1 + +# CHECK: FileHeader { +# CHECK-NEXT: Magic: 0x1DF +# CHECK-NEXT: NumberOfSections: 2 +# CHECK-NEXT: TimeStamp: None (0x0) +# CHECK-NEXT: SymbolTableOffset: 0x7A +# CHECK-NEXT: SymbolTableEntries: 4 +# CHECK-NEXT: OptionalHeaderSize: 0x0 +# CHECK-NEXT: Flags: 0x0 +# CHECK-NEXT: } +# CHECK-NEXT: Sections [ +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: PhysicalAddress: 0x0 +# CHECK-NEXT: VirtualAddress: 0x0 +# CHECK-NEXT: Size: 0x8 +# CHECK-NEXT: RawDataOffset: 0x64 +# CHECK-NEXT: RelocationPointer: 0x0 +# CHECK-NEXT: LineNumberPointer: 0x0 +# CHECK-NEXT: NumberOfRelocations: 0 +# CHECK-NEXT: NumberOfLineNumbers: 0 +# CHECK-NEXT: Type: STYP_TEXT (0x20) +# CHECK-NEXT: } +# CHECK-NEXT: Section { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .data +# CHECK-NEXT: PhysicalAddress: 0x8 +# CHECK-NEXT: VirtualAddress: 0x8 +# CHECK-NEXT: Size: 0x4 +# CHECK-NEXT: RawDataOffset: 0x6C +# CHECK-NEXT: RelocationPointer: 0x70 +# CHECK-NEXT: LineNumberPointer: 0x0 +# CHECK-NEXT: NumberOfRelocations: 1 +# CHECK-NEXT: NumberOfLineNumbers: 0 +# CHECK-NEXT: Type: STYP_DATA (0x40) +# CHECK-NEXT: } +# CHECK-NEXT: ] +# CHECK-NEXT: Symbols [ +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Index: 0 +# CHECK-NEXT: Name: .text +# CHECK-NEXT: Value (RelocatableAddress): 0x0 +# CHECK-NEXT: Section: .text +# CHECK-NEXT: Type: 0x0 +# CHECK-NEXT: StorageClass: C_STAT (0x3) +# CHECK-NEXT: NumberOfAuxEntries: 1 +# CHECK-NEXT: Sect Auxiliary Entry For Stat { +# CHECK-NEXT: Index: 1 +# CHECK-NEXT: SectionLength: 0 +# CHECK-NEXT: NumberOfRelocEnt: 0 +# CHECK-NEXT: NumberOfLineNum: 0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: Symbol { +# CHECK-NEXT: Index: 2 +# CHECK-NEXT: Name: .data +# CHECK-NEXT: Value (RelocatableAddress): 0x80 +# CHECK-NEXT: Section: .data +# CHECK-NEXT: Type: 0x0 +# CHECK-NEXT: StorageClass: C_STAT (0x3) +# CHECK-NEXT: NumberOfAuxEntries: 1 +# CHECK-NEXT: Sect Auxiliary Entry For Stat { +# CHECK-NEXT: Index: 3 +# CHECK-NEXT: SectionLength: 0 +# CHECK-NEXT: NumberOfRelocEnt: 0 +# CHECK-NEXT: NumberOfLineNum: 0 +# CHECK-NEXT: } +# CHECK-NEXT: } +# CHECK-NEXT: ] diff --git a/llvm/utils/gn/secondary/llvm/lib/ObjectYAML/BUILD.gn b/llvm/utils/gn/secondary/llvm/lib/ObjectYAML/BUILD.gn --- a/llvm/utils/gn/secondary/llvm/lib/ObjectYAML/BUILD.gn +++ b/llvm/utils/gn/secondary/llvm/lib/ObjectYAML/BUILD.gn @@ -26,6 +26,7 @@ "ObjectYAML.cpp", "WasmEmitter.cpp", "WasmYAML.cpp", + "XCOFFEmitter.cpp" "XCOFFYAML.cpp", "YAML.cpp", "yaml2obj.cpp",