[llvm] [llvm-readobj][COFF] Dump .modmeta section (PR #201695)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 8 12:57:15 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-binary-utilities

Author: Nerixyz (Nerixyz)

<details>
<summary>Changes</summary>

This adds the ability to dump the `.modmeta` section from MSVC generated object files. It stores metadata for C++ 20 modules and header units (see #<!-- -->174064). It lists all modules, their dependencies (presumably for initializers #<!-- -->174065), and their symbols (exported and non-exported).

The section is not documented, but dumpbin pretty prints it with `dumpbin /SECTION:.modmeta /RAWDATA`. For example, this is the output of the `cxx-modmeta-private-syms.yaml` test:

```
CXX MODULE METADATA:

  Header
    version             1
    reserved            0
    module index width  1 bytes
    symbol index width  1 bytes

  Modules

    0001: m
          Header Unit: no
          Dependents: 0003
          Symbols: 009 00C
          Export symbols: 00D 00F

    0003: o
          Header Unit: no
          Dependents:
          Symbols:
          Export symbols: 00E
```

The general structure of the module and name lists is explained in comments in `COFFCxxModuleMetadata`. More detailed info can be found in https://github.com/llvm/llvm-project/issues/174064#issuecomment-4018909816.

One thing I'm not too sure about is one byte between the module list and the name list. It's always zero, but it's ignored by dumpbin (changing it doesn't alter output). Right now it's skipped by the parser here as well.

---

Patch is 43.16 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/201695.diff


10 Files Affected:

- (added) llvm/include/llvm/Object/COFFCxxModuleMetadata.h (+117) 
- (modified) llvm/lib/Object/CMakeLists.txt (+1) 
- (added) llvm/lib/Object/COFFCxxModuleMetadata.cpp (+131) 
- (added) llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-headerunits.yaml (+253) 
- (added) llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-many-modules.yaml (+150) 
- (added) llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-private-syms.yaml (+220) 
- (modified) llvm/tools/llvm-readobj/COFFDumper.cpp (+74) 
- (modified) llvm/tools/llvm-readobj/ObjDumper.h (+1) 
- (modified) llvm/tools/llvm-readobj/Opts.td (+1) 
- (modified) llvm/tools/llvm-readobj/llvm-readobj.cpp (+4) 


``````````diff
diff --git a/llvm/include/llvm/Object/COFFCxxModuleMetadata.h b/llvm/include/llvm/Object/COFFCxxModuleMetadata.h
new file mode 100644
index 0000000000000..3cabb415d3bc5
--- /dev/null
+++ b/llvm/include/llvm/Object/COFFCxxModuleMetadata.h
@@ -0,0 +1,117 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Windows-specific.
+// Definitions and a parser for the C++ 20 ".modmeta" section.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_OBJECT_COFFMODULEMAP_H
+#define LLVM_OBJECT_COFFMODULEMAP_H
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+
+namespace llvm::object {
+
+struct COFFCxxModuleMetadataHeader {
+  uint8_t Version;
+  uint8_t Reserved;
+  /// Number of bytes used to encode module IDs.
+  uint8_t ModuleIndexWidth;
+  /// Number of bytes used to encode symbol IDs.
+  uint8_t SymbolIndexWidth;
+  /// Size of this header and the module lists.
+  support::ulittle32_t ModuleDataSize;
+};
+
+struct COFFCxxModuleMetadata {
+  uint8_t Version;
+  uint8_t Reserved;
+  /// Number of bytes used to encode module IDs.
+  uint8_t ModuleIndexWidth;
+  /// Number of bytes used to encode symbol IDs.
+  uint8_t SymbolIndexWidth;
+
+  /// Data for modules.
+  ///
+  /// Starts with a list of module IDs that are header units.
+  /// This is followed by a list of modules, which is terminated by the maximum
+  /// module ID (e.g. 0xff for Width=1). Each module starts with the ID followed
+  /// by a list of modules it depends on, a list of non-exported symbols, and a
+  /// list of exported symbols.
+  StringRef ModuleData;
+
+  /// List of null-terminated module names.
+  ///
+  /// The names are present in the order of the modules in \p ModuleData. Note
+  /// that the module with ID 0 does not have a name.
+  StringRef NamesData;
+};
+
+struct LLVM_ABI COFFCxxModuleMetadataReader {
+  COFFCxxModuleMetadataReader(const COFFCxxModuleMetadata &Map);
+
+  StringRef ModuleData;
+  StringRef NamesData;
+
+  uint8_t ModuleIndexWidth;
+  uint8_t SymbolIndexWidth;
+
+  bool hasModuleData() const;
+
+  Expected<uint32_t> readModuleID();
+  Expected<StringRef> readModuleName();
+
+  /// Read a list of modules.
+  ///
+  /// \param Visitor A callback that accepts an `ArrayRef` of `uint8_t`,
+  /// `ulittle16_t`, or `ulittle32_t` depending on the index width.
+  template <typename T> Error readModuleList(T &&Visitor) {
+    return readList(std::forward<T>(Visitor), ModuleIndexWidth);
+  }
+
+  /// Read a list of symbols.
+  ///
+  /// \param Visitor A callback that accepts an `ArrayRef` of `uint8_t`,
+  /// `ulittle16_t`, or `ulittle32_t` depending on the index width.
+  template <typename T> Error readSymbolList(T &&Visitor) {
+    return readList(std::forward<T>(Visitor), SymbolIndexWidth);
+  }
+
+private:
+  template <typename T> Error readList(T &&Visitor, uint8_t Width) {
+    Expected<ArrayRef<uint8_t>> List = readListImpl(Width);
+    if (!List)
+      return List.takeError();
+
+    if (Width == 1)
+      Visitor(*List);
+    else if (Width == 2)
+      Visitor(ArrayRef<support::ulittle16_t>(
+          reinterpret_cast<const support::ulittle16_t *>(List->data()),
+          List->size() / sizeof(support::ulittle16_t)));
+    else
+      Visitor(ArrayRef<support::ulittle32_t>(
+          reinterpret_cast<const support::ulittle32_t *>(List->data()),
+          List->size() / sizeof(support::ulittle32_t)));
+
+    return Error::success();
+  }
+
+  Expected<ArrayRef<uint8_t>> readListImpl(uint8_t Width);
+};
+
+LLVM_ABI Expected<COFFCxxModuleMetadata>
+parseCOFFCxxModuleMetadata(StringRef SectionData);
+
+} // namespace llvm::object
+
+#endif
diff --git a/llvm/lib/Object/CMakeLists.txt b/llvm/lib/Object/CMakeLists.txt
index 77a50f0d631d3..3635b4d6b8b6d 100644
--- a/llvm/lib/Object/CMakeLists.txt
+++ b/llvm/lib/Object/CMakeLists.txt
@@ -4,6 +4,7 @@ add_llvm_component_library(LLVMObject
   BBAddrMap.cpp
   Binary.cpp
   BuildID.cpp
+  COFFCxxModuleMetadata.cpp
   COFFImportFile.cpp
   COFFModuleDefinition.cpp
   COFFObjectFile.cpp
diff --git a/llvm/lib/Object/COFFCxxModuleMetadata.cpp b/llvm/lib/Object/COFFCxxModuleMetadata.cpp
new file mode 100644
index 0000000000000..0cffd8f836e37
--- /dev/null
+++ b/llvm/lib/Object/COFFCxxModuleMetadata.cpp
@@ -0,0 +1,131 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Object/COFFCxxModuleMetadata.h"
+#include "llvm/Support/ErrorExtras.h"
+
+namespace llvm::object {
+
+COFFCxxModuleMetadataReader::COFFCxxModuleMetadataReader(
+    const COFFCxxModuleMetadata &Map)
+    : ModuleData(Map.ModuleData), NamesData(Map.NamesData),
+      ModuleIndexWidth(Map.ModuleIndexWidth),
+      SymbolIndexWidth(Map.SymbolIndexWidth) {}
+
+bool COFFCxxModuleMetadataReader::hasModuleData() const {
+  return !ModuleData.empty();
+}
+
+Expected<uint32_t> COFFCxxModuleMetadataReader::readModuleID() {
+  switch (ModuleIndexWidth) {
+  case 1: {
+    if (ModuleData.size() < 1)
+      return createStringError("Not enough data");
+    uint8_t ID = static_cast<uint8_t>(ModuleData[0]);
+    ModuleData = ModuleData.slice(1, StringRef::npos);
+    if (ID == std::numeric_limits<uint8_t>::max())
+      return std::numeric_limits<uint32_t>::max();
+    return ID;
+  }
+  case 2: {
+    if (ModuleData.size() < 2)
+      return createStringError("Not enough data");
+    uint16_t ID =
+        support::endian::read<uint16_t>(ModuleData.data(), endianness::little);
+    ModuleData = ModuleData.slice(2, StringRef::npos);
+    if (ID == std::numeric_limits<uint16_t>::max())
+      return std::numeric_limits<uint32_t>::max();
+    return ID;
+  }
+  case 4: {
+    if (ModuleData.size() < 4)
+      return createStringError("Not enough data");
+    uint32_t ID =
+        support::endian::read<uint32_t>(ModuleData.data(), endianness::little);
+    ModuleData = ModuleData.slice(4, StringRef::npos);
+    return ID;
+  }
+  default:
+    return createStringErrorV("Unsupported index width: {0}", ModuleIndexWidth);
+  }
+}
+
+Expected<StringRef> COFFCxxModuleMetadataReader::readModuleName() {
+  size_t End = NamesData.find('\0');
+  if (End == StringRef::npos)
+    return createStringError("Missing null terminator");
+  StringRef Str = NamesData.slice(0, End);
+  NamesData = NamesData.drop_front(End + 1);
+  return Str;
+}
+
+Expected<ArrayRef<uint8_t>>
+COFFCxxModuleMetadataReader::readListImpl(uint8_t Width) {
+  StringRef Sentinel;
+  switch (Width) {
+  case 1:
+    Sentinel = "\xff";
+    break;
+  case 2:
+    Sentinel = "\xff\xff";
+    break;
+  case 4:
+    Sentinel = "\xff\xff\xff\xff";
+    break;
+  default:
+    return createStringErrorV("Unsupported index width: {0}", Width);
+  }
+  size_t Last = ModuleData.find(Sentinel);
+  if (Last == StringRef::npos)
+    return createStringError("Missing end sentinel");
+
+  ArrayRef<uint8_t> Data(ModuleData.bytes_begin(),
+                         ModuleData.bytes_begin() + Last);
+  ModuleData = ModuleData.drop_front(Last + Width);
+  return Data;
+}
+
+Expected<COFFCxxModuleMetadata>
+parseCOFFCxxModuleMetadata(StringRef SectionData) {
+  if (SectionData.size() <= sizeof(COFFCxxModuleMetadataHeader))
+    return createStringError("Insufficient size");
+
+  const auto *Header =
+      reinterpret_cast<const COFFCxxModuleMetadataHeader *>(SectionData.data());
+  if (Header->Version != 1)
+    return createStringError("Unsupported version");
+
+  auto IsSupportedIndexWidth = [](uint8_t Width) {
+    return Width == 1 || Width == 2 || Width == 4;
+  };
+
+  if (!IsSupportedIndexWidth(Header->ModuleIndexWidth))
+    return createStringErrorV("Unsupported module index width: {0}",
+                              Header->ModuleIndexWidth);
+  if (!IsSupportedIndexWidth(Header->SymbolIndexWidth))
+    return createStringErrorV("Unsupported symbol index width: {0}",
+                              Header->SymbolIndexWidth);
+
+  size_t ModuleDataSize = Header->ModuleDataSize.value();
+  if (ModuleDataSize <= sizeof(COFFCxxModuleMetadataHeader) ||
+      ModuleDataSize + 1 >= SectionData.size())
+    return createStringErrorV("Invalid module data size: {0}", ModuleDataSize);
+
+  COFFCxxModuleMetadata Map;
+  Map.Version = Header->Version;
+  Map.Reserved = Header->Reserved;
+  Map.ModuleIndexWidth = Header->ModuleIndexWidth;
+  Map.SymbolIndexWidth = Header->SymbolIndexWidth;
+  Map.ModuleData =
+      SectionData.slice(sizeof(COFFCxxModuleMetadataHeader), ModuleDataSize);
+  // Skip one reserved(?) byte.
+  Map.NamesData = SectionData.slice(ModuleDataSize + 1, StringRef::npos);
+  return Map;
+}
+
+} // namespace llvm::object
diff --git a/llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-headerunits.yaml b/llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-headerunits.yaml
new file mode 100644
index 0000000000000..4e2d4cec67dde
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-headerunits.yaml
@@ -0,0 +1,253 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-readobj --coff-cxx-module-metadata %t | FileCheck %s
+
+# CHECK:      CxxModuleMetadata {
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Reserved: 0
+# CHECK-NEXT:   ModuleIndexWidth: 1
+# CHECK-NEXT:   SymbolIndexWidth: 1
+# CHECK-NEXT:   Modules [
+# CHECK-NEXT:     CxxModule {
+# CHECK-NEXT:       ID: 0x0
+# CHECK-NEXT:       Name: 
+# CHECK-NEXT:       IsHeaderUnit: No
+# CHECK-NEXT:       Dependents: [0x1, 0x3, 0x25]
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: []
+# CHECK-NEXT:     }
+# CHECK-NEXT:     CxxModule {
+# CHECK-NEXT:       ID: 0x1
+# CHECK-NEXT:       Name: o
+# CHECK-NEXT:       IsHeaderUnit: No
+# CHECK-NEXT:       Dependents: []
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: [?getO@@YAHXZ::<!o> (16)]
+# CHECK-NEXT:     }
+# CHECK-NEXT:     CxxModule {
+# CHECK-NEXT:       ID: 0x3
+# CHECK-NEXT:       Name: {{.*}}/unit.hpp
+# CHECK-NEXT:       IsHeaderUnit: Yes
+# CHECK-NEXT:       Dependents: []
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: [?diff@@YAHHH at Z (14)]
+# CHECK-NEXT:     }
+# CHECK-NEXT:     CxxModule {
+# CHECK-NEXT:       ID: 0x25
+# CHECK-NEXT:       Name: {{.*}}/unit2.hpp
+# CHECK-NEXT:       IsHeaderUnit: Yes
+# CHECK-NEXT:       Dependents: []
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: [?sum@@YAHHH at Z (15)]
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT: }
+
+# This was created with the following commands and inputs:
+
+# cl unit.hpp /exportHeader /Founit.hpp.obj /std:c++20 /c
+# cl unit2.hpp /exportHeader /Founit2.hpp.obj /std:c++20 /c
+# cl o.ixx /std:c++20 /c                                   
+# cl /headerUnit unit.hpp=unit.hpp.ifc /headerUnit unit2.hpp=unit2.hpp.ifc main.cpp /std:c++20 /c
+
+# unit.hpp:
+# inline int diff(int a, int b) { return a - b; }
+
+# unit2.hpp:
+# inline int sum(int a, int b) { return a + b; }
+
+# o.ixx:
+# export module o;
+# int foo = 42;
+# export int getO() { return foo; }
+
+# main.cpp:
+# import "unit.hpp";
+# import "unit2.hpp";
+# import o;
+# int main() {
+#   int d = diff(2, 3);
+#   return sum(1, d) + getO();
+# }
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .modmeta
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     01000101220000000325FF00010325FFFFFF01FFFF10FF03FFFF0EFF25FFFF0FFFFF006F00463A2F4465762F64756D6D792F686561646572756E6974732F756E69742E68707000463A2F4465762F64756D6D792F686561646572756E6974732F756E6974322E68707000
+    SizeOfRawData:   106
+symbols:
+  - Name:            '@comp.id'
+    Value:           17140626
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@feat.00'
+    Value:           2147549584
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            '@vol.md'
+    Value:           3
+    SectionNumber:   -1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .drectve
+    Value:           0
+    SectionNumber:   1
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          47
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.debug$S'
+    Value:           0
+    SectionNumber:   2
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          116
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          59
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        3944583797
+      Number:          0
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          21
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        2168134607
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            '.text$mn'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          21
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        1888124682
+      Number:          0
+      Selection:       IMAGE_COMDAT_SELECT_ANY
+  - Name:            main
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?diff@@YAHHH at Z'
+    Value:           0
+    SectionNumber:   4
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?sum@@YAHHH at Z'
+    Value:           0
+    SectionNumber:   5
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '?getO@@YAHXZ::<!o>'
+    Value:           0
+    SectionNumber:   0
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_FUNCTION
+    StorageClass:    IMAGE_SYM_CLASS_EXTERNAL
+  - Name:            '$LN3'
+    Value:           0
+    SectionNumber:   3
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_LABEL
+  - Name:            .xdata
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          8
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        931692337
+      Number:          0
+  - Name:            '$unwind$main'
+    Value:           0
+    SectionNumber:   6
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .pdata
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          12
+      NumberOfRelocations: 3
+      NumberOfLinenumbers: 0
+      CheckSum:        3634843435
+      Number:          0
+  - Name:            '$pdata$main'
+    Value:           0
+    SectionNumber:   7
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+  - Name:            .modmeta
+    Value:           0
+    SectionNumber:   8
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          106
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+  - Name:            .chks64
+    Value:           0
+    SectionNumber:   9
+    SimpleType:      IMAGE_SYM_TYPE_NULL
+    ComplexType:     IMAGE_SYM_DTYPE_NULL
+    StorageClass:    IMAGE_SYM_CLASS_STATIC
+    SectionDefinition:
+      Length:          72
+      NumberOfRelocations: 0
+      NumberOfLinenumbers: 0
+      CheckSum:        0
+      Number:          0
+...
diff --git a/llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-many-modules.yaml b/llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-many-modules.yaml
new file mode 100644
index 0000000000000..a968050c34c2e
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/cxx-modmeta-many-modules.yaml
@@ -0,0 +1,150 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-readobj --coff-cxx-module-metadata %t | FileCheck %s
+
+# CHECK:      CxxModuleMetadata {
+# CHECK-NEXT:   Version: 1
+# CHECK-NEXT:   Reserved: 0
+# CHECK-NEXT:   ModuleIndexWidth: 2
+# CHECK-NEXT:   SymbolIndexWidth: 1
+# CHECK-NEXT:   Modules [
+# CHECK-NEXT:     CxxModule {
+# CHECK-NEXT:       ID: 0x0
+# CHECK-NEXT:       Name: 
+# CHECK-NEXT:       IsHeaderUnit: No
+# CHECK-NEXT:       Dependents: [0x1, 0x7, 0xE, 0x13, 0x1A, 0x21, {{.*}} 0x685, 0x68C]
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: []
+# CHECK-NEXT:     }
+# CHECK-NEXT:     CxxModule {
+# CHECK-NEXT:       ID: 0x1
+# CHECK-NEXT:       Name: mod45
+# CHECK-NEXT:       IsHeaderUnit: No
+# CHECK-NEXT:       Dependents: []
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: []
+# CHECK-NEXT:     }
+# CHECK-NEXT:     CxxModule {
+# CHECK-NEXT:       ID: 0x7
+# CHECK-NEXT:       Name: mod249
+# CHECK-NEXT:       IsHeaderUnit: No
+# CHECK-NEXT:       Dependents: []
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: []
+# CHECK-NEXT:     }
+
+# CHECK:            ID: 0x685
+# CHECK-NEXT:       Name: mod177
+# CHECK-NEXT:       IsHeaderUnit: No
+# CHECK-NEXT:       Dependents: []
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: []
+# CHECK-NEXT:     }
+# CHECK-NEXT:     CxxModule {
+# CHECK-NEXT:       ID: 0x68C
+# CHECK-NEXT:       Name: mod132
+# CHECK-NEXT:       IsHeaderUnit: No
+# CHECK-NEXT:       Dependents: []
+# CHECK-NEXT:       Symbols: []
+# CHECK-NEXT:       Exports: []
+# CHECK-NEXT:     }
+# CHECK-NEXT:   ]
+# CHECK-NEXT: }
+
+# This was created by compiling a module with 256 dependencies named `mod{i}`.
+
+--- !COFF
+header:
+  Machine:         IMAGE_FILE_MACHINE_AMD64
+  Characteristics: [  ]
+sections:
+  - Name:            .modmeta
+    Characteristics: [ IMAGE_SCN_LNK_INFO, IMAGE_SCN_LNK_REMOVE ]
+    Alignment:       1
+    SectionData:     0100020112080000FFFF0000010007000E0013001A00210028002F0036003D0043004A00500056005C0063006A00710078007E0084008B0092009900A000A700AC00B200B800BE00C500CC00D300D900DF00E600ED00F400FB00010107010C0113011A01210128012F0136013C01430149014F0156015C0163016A01710177017D0184018B0192019901A001A501AA01B001B601BD01C...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/201695


More information about the llvm-commits mailing list