[yaml2obj] Add support for structured COFF section data.
authorJacek Caban <jacek@codeweavers.com>
Fri, 28 Apr 2023 12:28:00 +0000 (14:28 +0200)
committerJacek Caban <jacek@codeweavers.com>
Wed, 5 Jul 2023 11:06:37 +0000 (13:06 +0200)
Reviewed By: jhenderson
Differential Revision: https://reviews.llvm.org/D149439

llvm/docs/yaml2obj.rst
llvm/include/llvm/ObjectYAML/COFFYAML.h
llvm/lib/ObjectYAML/COFFEmitter.cpp
llvm/lib/ObjectYAML/COFFYAML.cpp
llvm/test/tools/llvm-readobj/arm64ec-chpe.yaml
llvm/test/tools/yaml2obj/COFF/invalid-raw-data.yaml [new file with mode: 0644]
llvm/test/tools/yaml2obj/COFF/mixed-data.yaml [new file with mode: 0644]
llvm/test/tools/yaml2obj/COFF/structured-data.yaml [new file with mode: 0644]

index d18ce02..a0bca06 100644 (file)
@@ -29,6 +29,11 @@ Here's a sample COFF file.
                        ] # 0x60500020
       SectionData:
         "\x83\xEC\x0C\xC7\x44\x24\x08\x00\x00\x00\x00\xC7\x04\x24\x00\x00\x00\x00\xE8\x00\x00\x00\x00\xE8\x00\x00\x00\x00\x8B\x44\x24\x08\x83\xC4\x0C\xC3" # |....D$.......$...............D$.....|
+    - Name: .rdata
+      Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+      StructuredData:
+        - Binary: {type: str}
+        - UInt32: {type: int}
 
   symbols:
     - Name: .text
index fbd8298..1d941ae 100644 (file)
@@ -66,6 +66,14 @@ struct Relocation {
   std::optional<uint32_t> SymbolTableIndex;
 };
 
+struct SectionDataEntry {
+  std::optional<uint32_t> UInt32;
+  yaml::BinaryRef Binary;
+
+  size_t size() const;
+  void writeAsBinary(raw_ostream &OS) const;
+};
+
 struct Section {
   COFF::section Header;
   unsigned Alignment = 0;
@@ -74,6 +82,7 @@ struct Section {
   std::vector<CodeViewYAML::LeafRecord> DebugT;
   std::vector<CodeViewYAML::LeafRecord> DebugP;
   std::optional<CodeViewYAML::DebugHSection> DebugH;
+  std::vector<SectionDataEntry> StructuredData;
   std::vector<Relocation> Relocations;
   StringRef Name;
 
@@ -117,6 +126,7 @@ struct Object {
 LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Section)
 LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Symbol)
 LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::Relocation)
+LLVM_YAML_IS_SEQUENCE_VECTOR(COFFYAML::SectionDataEntry)
 
 namespace llvm {
 namespace yaml {
@@ -241,6 +251,10 @@ struct MappingTraits<COFFYAML::Symbol> {
   static void mapping(IO &IO, COFFYAML::Symbol &S);
 };
 
+template <> struct MappingTraits<COFFYAML::SectionDataEntry> {
+  static void mapping(IO &IO, COFFYAML::SectionDataEntry &Sec);
+};
+
 template <>
 struct MappingTraits<COFFYAML::Section> {
   static void mapping(IO &IO, COFFYAML::Section &Sec);
index f8a285d..b4ce90d 100644 (file)
@@ -242,10 +242,13 @@ static bool layoutCOFF(COFFParser &CP) {
         S.SectionData = CodeViewYAML::toDebugH(*S.DebugH, CP.Allocator);
     }
 
-    if (S.SectionData.binary_size() > 0) {
+    size_t DataSize = S.SectionData.binary_size();
+    for (auto E : S.StructuredData)
+      DataSize += E.size();
+    if (DataSize > 0) {
       CurrentSectionDataOffset = alignTo(CurrentSectionDataOffset,
                                          CP.isPE() ? CP.getFileAlignment() : 4);
-      S.Header.SizeOfRawData = S.SectionData.binary_size();
+      S.Header.SizeOfRawData = DataSize;
       if (CP.isPE())
         S.Header.SizeOfRawData =
             alignTo(S.Header.SizeOfRawData, CP.getFileAlignment());
@@ -496,9 +499,12 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
       continue;
     assert(S.Header.PointerToRawData >= OS.tell());
     OS.write_zeros(S.Header.PointerToRawData - OS.tell());
+    for (auto E : S.StructuredData)
+      E.writeAsBinary(OS);
     S.SectionData.writeAsBinary(OS);
     assert(S.Header.SizeOfRawData >= S.SectionData.binary_size());
-    OS.write_zeros(S.Header.SizeOfRawData - S.SectionData.binary_size());
+    OS.write_zeros(S.Header.PointerToRawData + S.Header.SizeOfRawData -
+                   OS.tell());
     if (S.Header.Characteristics & COFF::IMAGE_SCN_LNK_NRELOC_OVFL)
       OS << binary_le<uint32_t>(/*VirtualAddress=*/ S.Relocations.size() + 1)
          << binary_le<uint32_t>(/*SymbolTableIndex=*/ 0)
@@ -588,6 +594,19 @@ static bool writeCOFF(COFFParser &CP, raw_ostream &OS) {
   return true;
 }
 
+size_t COFFYAML::SectionDataEntry::size() const {
+  size_t Size = Binary.binary_size();
+  if (UInt32)
+    Size += sizeof(*UInt32);
+  return Size;
+}
+
+void COFFYAML::SectionDataEntry::writeAsBinary(raw_ostream &OS) const {
+  if (UInt32)
+    OS << binary_le(*UInt32);
+  Binary.writeAsBinary(OS);
+}
+
 namespace llvm {
 namespace yaml {
 
index fe9a9f8..5ef634c 100644 (file)
@@ -547,6 +547,12 @@ void MappingTraits<COFF::AuxiliaryCLRToken>::mapping(
   IO.mapRequired("SymbolTableIndex", ACT.SymbolTableIndex);
 }
 
+void MappingTraits<COFFYAML::SectionDataEntry>::mapping(
+    IO &IO, COFFYAML::SectionDataEntry &E) {
+  IO.mapOptional("UInt32", E.UInt32);
+  IO.mapOptional("Binary", E.Binary);
+}
+
 void MappingTraits<COFFYAML::Symbol>::mapping(IO &IO, COFFYAML::Symbol &S) {
   MappingNormalization<NStorageClass, uint8_t> NS(IO, S.Header.StorageClass);
 
@@ -586,9 +592,16 @@ void MappingTraits<COFFYAML::Section>::mapping(IO &IO, COFFYAML::Section &Sec) {
   else if (Sec.Name == ".debug$H")
     IO.mapOptional("GlobalHashes", Sec.DebugH);
 
+  IO.mapOptional("StructuredData", Sec.StructuredData);
+
+  if (!Sec.StructuredData.empty() && Sec.SectionData.binary_size()) {
+    IO.setError("StructuredData and SectionData can't be used together");
+    return;
+  }
+
   // Uninitialized sections, such as .bss, typically have no data, but the size
   // is carried in SizeOfRawData, even though PointerToRawData is zero.
-  if (Sec.SectionData.binary_size() == 0 &&
+  if (Sec.SectionData.binary_size() == 0 && Sec.StructuredData.empty() &&
       NC->Characteristics & COFF::IMAGE_SCN_CNT_UNINITIALIZED_DATA)
     IO.mapOptional("SizeOfRawData", Sec.Header.SizeOfRawData);
 
index 629fe02..e3758da 100644 (file)
@@ -44,6 +44,42 @@ sections:
     Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ, IMAGE_SCN_MEM_WRITE ]
     VirtualAddress:  0x5000
     VirtualSize:     144
-    SectionData:     '010000005050000003000000685000008050000000000000000000000000000000000000000000000000000000000000020000000200000000000000000000000000000000000000000000000000000001100000300000000020000040000000023000005000000000100000201000000010000020100000401000000020000000100000002000002010000030200000'
+    StructuredData:
+      - UInt32: 1       # Version
+      - UInt32: 0x5050  # CodeMap
+      - UInt32: 3       # CodeMapCount
+      - UInt32: 0x5068  # CodeRangesToEntryPoints
+      - UInt32: 0x5080  # RedirectionMetadata
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 2       # CodeRangesToEntryPointsCount
+      - UInt32: 2       # RedirectionMetadataCount
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0
+      - UInt32: 0x1001  # CodeMap[0]
+      - UInt32: 0x30
+      - UInt32: 0x2000  # CodeMap[1]
+      - UInt32: 0x40
+      - UInt32: 0x3002  # CodeMap[2]
+      - UInt32: 0x50
+      - UInt32: 0x1000  # CodeRangesToEntryPoints[0]
+      - UInt32: 0x1020
+      - UInt32: 0x1000
+      - UInt32: 0x1020  # CodeRangesToEntryPoints[1]
+      - UInt32: 0x1040
+      - UInt32: 0x2000
+      - UInt32: 0x1000  # RedirectionMetadata[0]
+      - UInt32: 0x2000
+      - UInt32: 0x1020  # RedirectionMetadata[1]
+      - UInt32: 0x2030
 symbols:         []
 ...
diff --git a/llvm/test/tools/yaml2obj/COFF/invalid-raw-data.yaml b/llvm/test/tools/yaml2obj/COFF/invalid-raw-data.yaml
new file mode 100644 (file)
index 0000000..62445fa
--- /dev/null
@@ -0,0 +1,22 @@
+# RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s
+# CHECK: YAML:18:5: error: unknown key 'SizeOfRawData'
+
+--- !COFF
+OptionalHeader:
+  ImageBase:        0x180000000
+  SectionAlignment: 4096
+  FileAlignment:    512
+  DLLCharacteristics: [ ]
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_DLL ]
+sections:
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_UNINITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  0x1000
+    VirtualSize:     20
+    SizeOfRawData:   4
+    StructuredData:
+        - UInt32: 1
+symbols: []
+...
diff --git a/llvm/test/tools/yaml2obj/COFF/mixed-data.yaml b/llvm/test/tools/yaml2obj/COFF/mixed-data.yaml
new file mode 100644 (file)
index 0000000..7f23f4d
--- /dev/null
@@ -0,0 +1,22 @@
+# RUN: not yaml2obj %s -o %t 2>&1 | FileCheck %s
+# CHECK: error: StructuredData and SectionData can't be used together
+
+--- !COFF
+OptionalHeader:
+  ImageBase:        0x180000000
+  SectionAlignment: 4096
+  FileAlignment:    512
+  DLLCharacteristics: [ ]
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_DLL ]
+sections:
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  0x1000
+    VirtualSize:     20
+    SectionData:     55
+    StructuredData:
+        - UInt32: 1
+symbols: []
+...
diff --git a/llvm/test/tools/yaml2obj/COFF/structured-data.yaml b/llvm/test/tools/yaml2obj/COFF/structured-data.yaml
new file mode 100644 (file)
index 0000000..687c43d
--- /dev/null
@@ -0,0 +1,25 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-readobj --hex-dump=.rdata %t | FileCheck %s
+# CHECK:  0x180001000 01000000 02000000 11223344 ffffffff
+
+--- !COFF
+OptionalHeader:
+  ImageBase:        0x180000000
+  SectionAlignment: 4096
+  FileAlignment:    512
+  DLLCharacteristics: [ ]
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [ IMAGE_FILE_EXECUTABLE_IMAGE, IMAGE_FILE_LARGE_ADDRESS_AWARE, IMAGE_FILE_DLL ]
+sections:
+  - Name:            .rdata
+    Characteristics: [ IMAGE_SCN_CNT_INITIALIZED_DATA, IMAGE_SCN_MEM_READ ]
+    VirtualAddress:  0x1000
+    VirtualSize:     20
+    StructuredData:
+        - UInt32: 1
+        - UInt32: 2
+        - Binary: 11223344
+        - UInt32: 0xffffffff
+symbols: []
+...