[llvm] 50bb1b9 - [yaml2obj] Initial the support of yaml2obj for 32-bit XCOFF.

via llvm-commits llvm-commits at lists.llvm.org
Sun Jun 6 21:15:28 PDT 2021


Author: Esme-Yi
Date: 2021-06-07T04:14:44Z
New Revision: 50bb1b930dbce6ac2bd6af599f2e2a7d00f36ea5

URL: https://github.com/llvm/llvm-project/commit/50bb1b930dbce6ac2bd6af599f2e2a7d00f36ea5
DIFF: https://github.com/llvm/llvm-project/commit/50bb1b930dbce6ac2bd6af599f2e2a7d00f36ea5.diff

LOG: [yaml2obj] Initial the support of yaml2obj for 32-bit XCOFF.

Summary: The patch implements the mapping of the Yaml
information to XCOFF object file to enable the yaml2obj
tool for XCOFF. Currently only 32-bit is supported.

Reviewed By: jhenderson, shchenz

Differential Revision: https://reviews.llvm.org/D95505

Added: 
    llvm/lib/ObjectYAML/XCOFFEmitter.cpp
    llvm/test/tools/yaml2obj/XCOFF/basic-doc.yaml
    llvm/test/tools/yaml2obj/XCOFF/full-contents.yaml

Modified: 
    llvm/include/llvm/BinaryFormat/XCOFF.h
    llvm/include/llvm/ObjectYAML/ObjectYAML.h
    llvm/include/llvm/ObjectYAML/XCOFFYAML.h
    llvm/include/llvm/ObjectYAML/yaml2obj.h
    llvm/lib/ObjectYAML/CMakeLists.txt
    llvm/lib/ObjectYAML/ObjectYAML.cpp
    llvm/lib/ObjectYAML/XCOFFYAML.cpp
    llvm/lib/ObjectYAML/yaml2obj.cpp
    llvm/utils/gn/secondary/llvm/lib/ObjectYAML/BUILD.gn

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/XCOFF.h b/llvm/include/llvm/BinaryFormat/XCOFF.h
index 803a3ab04fc75..3fcf302366abb 100644
--- a/llvm/include/llvm/BinaryFormat/XCOFF.h
+++ b/llvm/include/llvm/BinaryFormat/XCOFF.h
@@ -33,6 +33,8 @@ constexpr uint8_t AllocRegNo = 31;
 
 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
index dd26ce3e9703b..312777aadd4c3 100644
--- 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 <memory>
 
@@ -31,6 +32,7 @@ struct YamlObjectFile {
   std::unique_ptr<MachOYAML::UniversalBinary> FatMachO;
   std::unique_ptr<MinidumpYAML::Object> Minidump;
   std::unique_ptr<WasmYAML::Object> Wasm;
+  std::unique_ptr<XCOFFYAML::Object> Xcoff;
 };
 
 template <> struct MappingTraits<YamlObjectFile> {

diff  --git a/llvm/include/llvm/ObjectYAML/XCOFFYAML.h b/llvm/include/llvm/ObjectYAML/XCOFFYAML.h
index f99004e69762f..2630175642c40 100644
--- a/llvm/include/llvm/ObjectYAML/XCOFFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/XCOFFYAML.h
@@ -23,32 +23,62 @@ struct FileHeader {
   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<Relocation> 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<Section> Sections;
   std::vector<Symbol> 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<XCOFF::SectionTypeFlags> {
+  static void bitset(IO &IO, XCOFF::SectionTypeFlags &Value);
+};
+
 template <> struct ScalarEnumerationTraits<XCOFF::StorageClass> {
   static void enumeration(IO &IO, XCOFF::StorageClass &Value);
 };
@@ -57,14 +87,23 @@ template <> struct MappingTraits<XCOFFYAML::FileHeader> {
   static void mapping(IO &IO, XCOFFYAML::FileHeader &H);
 };
 
-template <> struct MappingTraits<XCOFFYAML::Object> {
-  static void mapping(IO &IO, XCOFFYAML::Object &Obj);
-};
 
 template <> struct MappingTraits<XCOFFYAML::Symbol> {
   static void mapping(IO &IO, XCOFFYAML::Symbol &S);
 };
 
+template <> struct MappingTraits<XCOFFYAML::Relocation> {
+  static void mapping(IO &IO, XCOFFYAML::Relocation &R);
+};
+
+template <> struct MappingTraits<XCOFFYAML::Section> {
+  static void mapping(IO &IO, XCOFFYAML::Section &Sec);
+};
+
+template <> struct MappingTraits<XCOFFYAML::Object> {
+  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
index 21dabb8597d4c..468f673fd4510 100644
--- a/llvm/include/llvm/ObjectYAML/yaml2obj.h
+++ b/llvm/include/llvm/ObjectYAML/yaml2obj.h
@@ -40,6 +40,10 @@ namespace WasmYAML {
 struct Object;
 }
 
+namespace XCOFFYAML {
+struct Object;
+}
+
 namespace ArchYAML {
 struct Archive;
 }
@@ -58,6 +62,7 @@ bool yaml2macho(YamlObjectFile &Doc, raw_ostream &Out, ErrorHandler EH);
 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
index ee241f86d25b8..acb9f7cd11aea 100644
--- a/llvm/lib/ObjectYAML/CMakeLists.txt
+++ b/llvm/lib/ObjectYAML/CMakeLists.txt
@@ -18,6 +18,7 @@ add_llvm_component_library(LLVMObjectYAML
   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
index 4564b537c9a14..63769d2eba0e4 100644
--- a/llvm/lib/ObjectYAML/ObjectYAML.cpp
+++ b/llvm/lib/ObjectYAML/ObjectYAML.cpp
@@ -59,6 +59,9 @@ void MappingTraits<YamlObjectFile>::mapping(IO &IO,
     } else if (IO.mapTag("!WASM")) {
       ObjectFile.Wasm.reset(new WasmYAML::Object());
       MappingTraits<WasmYAML::Object>::mapping(IO, *ObjectFile.Wasm);
+    } else if (IO.mapTag("!XCOFF")) {
+      ObjectFile.Xcoff.reset(new XCOFFYAML::Object());
+      MappingTraits<XCOFFYAML::Object>::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
index 0000000000000..67c890eebd775
--- /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<StringRef, int16_t> 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<XCOFFYAML::Section> 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<char> 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<uint16_t>(Obj.Header.Magic ? Obj.Header.Magic : InitFileHdr.Magic);
+  W.write<uint16_t>(Obj.Header.NumberOfSections ? Obj.Header.NumberOfSections
+                                                : InitFileHdr.NumberOfSections);
+  W.write<int32_t>(Obj.Header.TimeStamp);
+  W.write<uint32_t>(Obj.Header.SymbolTableOffset
+                        ? Obj.Header.SymbolTableOffset
+                        : InitFileHdr.SymbolTableOffset);
+  W.write<int32_t>(Obj.Header.NumberOfSymTableEntries
+                       ? Obj.Header.NumberOfSymTableEntries
+                       : InitFileHdr.NumberOfSymTableEntries);
+  W.write<uint16_t>(Obj.Header.AuxHeaderSize);
+  W.write<uint16_t>(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<uint32_t>(SectionAddress); // Physical address
+    W.write<uint32_t>(SectionAddress); // Virtual address
+    W.write<uint32_t>(YamlSec.Size ? YamlSec.Size : DerivedSec.Size);
+    W.write<uint32_t>(YamlSec.FileOffsetToData ? YamlSec.FileOffsetToData
+                                               : DerivedSec.FileOffsetToData);
+    W.write<uint32_t>(YamlSec.FileOffsetToRelocations
+                          ? YamlSec.FileOffsetToRelocations
+                          : DerivedSec.FileOffsetToRelocations);
+    W.write<uint32_t>(YamlSec.FileOffsetToLineNumbers);
+    W.write<uint16_t>(YamlSec.NumberOfRelocations
+                          ? YamlSec.NumberOfRelocations
+                          : DerivedSec.NumberOfRelocations);
+    W.write<uint16_t>(YamlSec.NumberOfLineNumbers);
+    W.write<int32_t>(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<uint32_t>(YamlRel.VirtualAddress);
+        W.write<uint32_t>(YamlRel.SymbolIndex);
+        W.write<uint8_t>(YamlRel.Info);
+        W.write<uint8_t>(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<uint32_t>(YamlSym.Value);
+    W.write<int16_t>(
+        YamlSym.SectionName.size() ? SectionIndexMap[YamlSym.SectionName] : 0);
+    W.write<uint16_t>(YamlSym.Type);
+    W.write<uint8_t>(YamlSym.StorageClass);
+    W.write<uint8_t>(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
index 982e6aecbb987..73d188e274b12 100644
--- a/llvm/lib/ObjectYAML/XCOFFYAML.cpp
+++ b/llvm/lib/ObjectYAML/XCOFFYAML.cpp
@@ -23,6 +23,25 @@ Object::Object() { memset(&Header, 0, sizeof(Header)); }
 
 namespace yaml {
 
+void ScalarBitSetTraits<XCOFF::SectionTypeFlags>::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<XCOFF::StorageClass>::enumeration(
     IO &IO, XCOFF::StorageClass &Value) {
 #define ECase(X) IO.enumCase(Value, #X, XCOFF::X)
@@ -79,30 +98,64 @@ void ScalarEnumerationTraits<XCOFF::StorageClass>::enumeration(
 #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<XCOFFYAML::FileHeader>::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<XCOFFYAML::Relocation>::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<XCOFFYAML::Section>::mapping(IO &IO,
+                                                XCOFFYAML::Section &Sec) {
+  MappingNormalization<NSectionFlags, uint32_t> 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<XCOFFYAML::Symbol>::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<XCOFFYAML::Object>::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
index ef2ab83dcd24e..d19fa0a525302 100644
--- a/llvm/lib/ObjectYAML/yaml2obj.cpp
+++ b/llvm/lib/ObjectYAML/yaml2obj.cpp
@@ -44,6 +44,8 @@ bool convertYAML(yaml::Input &YIn, raw_ostream &Out, ErrorHandler ErrHandler,
       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
index 0000000000000..5d9ec19afa931
--- /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
index 0000000000000..5fb17c7ac7e1e
--- /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
index 0f6c2e8ea3cf7..9f80c4f4813cf 100644
--- a/llvm/utils/gn/secondary/llvm/lib/ObjectYAML/BUILD.gn
+++ b/llvm/utils/gn/secondary/llvm/lib/ObjectYAML/BUILD.gn
@@ -26,6 +26,7 @@ static_library("ObjectYAML") {
     "ObjectYAML.cpp",
     "WasmEmitter.cpp",
     "WasmYAML.cpp",
+    "XCOFFEmitter.cpp"
     "XCOFFYAML.cpp",
     "YAML.cpp",
     "yaml2obj.cpp",


        


More information about the llvm-commits mailing list