[lld] [llvm] [LLD][COFF] Add more variety of CET flags (PR #150761)

via llvm-commits llvm-commits at lists.llvm.org
Sat Jul 26 06:16:18 PDT 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-lld-coff

Author: None (kkent030315)

<details>
<summary>Changes</summary>

Those are all MS link.exe compatible flags.

### CET (Control-flow Enforcement Technology) family
- Added `/cetcompatstrict[:no]` flag in LLD/COFF
- Added `/cetipvalidationrelaxed[:no]` flag in LLD/COFF
- Added `/cetdynamicapisinproc[:no]` flag in LLD/COFF

### Misc
- Added `/hotpatchcompatible[:no]` flag in LLD/COFF

---
Full diff: https://github.com/llvm/llvm-project/pull/150761.diff


11 Files Affected:

- (modified) lld/COFF/Config.h (+4) 
- (modified) lld/COFF/Driver.cpp (+7) 
- (modified) lld/COFF/Options.td (+8) 
- (modified) lld/COFF/Writer.cpp (+24-2) 
- (modified) lld/test/COFF/options.test (+40) 
- (modified) llvm/include/llvm/BinaryFormat/COFF.h (+16-1) 
- (added) llvm/test/tools/llvm-readobj/COFF/cetcompatstrict.test (+16) 
- (added) llvm/test/tools/llvm-readobj/COFF/cetdynamicapisinproc.test (+16) 
- (added) llvm/test/tools/llvm-readobj/COFF/cetipvalidationrelaxed.test (+16) 
- (added) llvm/test/tools/llvm-readobj/COFF/hotpatchcompatible.test (+16) 
- (modified) llvm/tools/llvm-readobj/COFFDumper.cpp (+8-1) 


``````````diff
diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 91b6e632fa7ed..95491c51bb7cd 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -307,6 +307,10 @@ struct Configuration {
   bool dynamicBase = true;
   bool allowBind = true;
   bool cetCompat = false;
+  bool cetCompatStrict = false;
+  bool cetCompatIpValidationRelaxed = false;
+  bool cetCompatDynamicApisInProcOnly = false;
+  bool hotpatchCompat = false;
   bool nxCompat = true;
   bool allowIsolation = true;
   bool terminalServerAware = true;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index 83040b534be9c..8cdadb2068ccd 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2145,6 +2145,13 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   config->integrityCheck =
       args.hasFlag(OPT_integritycheck, OPT_integritycheck_no, false);
   config->cetCompat = args.hasFlag(OPT_cetcompat, OPT_cetcompat_no, false);
+  config->cetCompatStrict = args.hasFlag(OPT_cetcompatstrict, OPT_cetcompatstrict_no, false);
+  config->cetCompatIpValidationRelaxed =
+      args.hasFlag(OPT_cetipvalidationrelaxed, OPT_cetipvalidationrelaxed_no, false);
+  config->cetCompatDynamicApisInProcOnly =
+      args.hasFlag(OPT_cetdynamicapisinproc, OPT_cetdynamicapisinproc_no, false);
+  config->hotpatchCompat =
+    args.hasFlag(OPT_hotpatchcompatible, OPT_hotpatchcompatible_no, false);
   config->nxCompat = args.hasFlag(OPT_nxcompat, OPT_nxcompat_no, true);
   for (auto *arg : args.filtered(OPT_swaprun))
     parseSwaprun(arg->getValue());
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index 2a82fb5cd8845..da2e4706fa606 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -196,6 +196,14 @@ defm appcontainer : B<"appcontainer",
                       "Image can run outside an app container (default)">;
 defm cetcompat : B<"cetcompat", "Mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack",
                    "Don't mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack (default)">;
+defm cetcompatstrict : B<"cetcompatstrict", "Mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack in strict mode",
+                         "Don't mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack in strict mode (default)">;
+defm cetipvalidationrelaxed : B<"cetipvalidationrelaxed", "Mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack with relaxed context IP validation",
+                                "Don't mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack with relaxed context IP validation (default)">;
+defm cetdynamicapisinproc : B<"cetdynamicapisinproc", "Mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack in such a way that dynamic APIs allowed in process",
+                              "Don't mark executable image as compatible with Control-flow Enforcement Technology (CET) Shadow Stack with dynamic APIs allowed in process (default)">;
+defm hotpatchcompatible : B<"hotpatchcompatible", "Mark executable image as compatible with hotpatch",
+                            "Don't mark executable image as compatible with hotpatch (default)">;
 defm dynamicbase : B<"dynamicbase", "Enable ASLR (default unless /fixed)",
                      "Disable ASLR (default when /fixed)">;
 defm fixed : B<"fixed", "Disable base relocations",
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 076561807af47..5c72cca522feb 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -1216,7 +1216,9 @@ void Writer::createMiscChunks() {
   // Create Debug Information Chunks
   debugInfoSec = config->mingw ? buildidSec : rdataSec;
   if (config->buildIDHash != BuildIDHash::None || config->debug ||
-      config->repro || config->cetCompat) {
+      config->repro || config->cetCompat || config->cetCompatStrict ||
+      config->cetCompatIpValidationRelaxed ||
+      config->cetCompatDynamicApisInProcOnly || config->hotpatchCompat) {
     debugDirectory =
         make<DebugDirectoryChunk>(ctx, debugRecords, config->repro);
     debugDirectory->setAlignment(4);
@@ -1237,10 +1239,30 @@ void Writer::createMiscChunks() {
     });
   }
 
+  uint16_t ex_characteristics_flags = 0;
   if (config->cetCompat) {
+    ex_characteristics_flags |= IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT;
+  }
+  if (config->cetCompatStrict) {
+    ex_characteristics_flags |=
+        IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE;
+  }
+  if (config->cetCompatIpValidationRelaxed) {
+    ex_characteristics_flags |= 
+        IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE;
+  }
+  if (config->cetCompatDynamicApisInProcOnly) {
+    ex_characteristics_flags |= 
+        IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY;
+  }
+  if (config->hotpatchCompat) {
+    ex_characteristics_flags |= IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE;
+  }
+
+  if (ex_characteristics_flags) {
     debugRecords.emplace_back(COFF::IMAGE_DEBUG_TYPE_EX_DLLCHARACTERISTICS,
                               make<ExtendedDllCharacteristicsChunk>(
-                                  IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT));
+                                  ex_characteristics_flags));
   }
 
   // Align and add each chunk referenced by the debug data directory.
diff --git a/lld/test/COFF/options.test b/lld/test/COFF/options.test
index 0dd889042869a..d131169eada61 100644
--- a/lld/test/COFF/options.test
+++ b/lld/test/COFF/options.test
@@ -60,6 +60,46 @@ CETCOMPAT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT
 # RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETCOMPAT %s
 NONCETCOMPAT-NOT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT
 
+# RUN: lld-link /out:%t.exe /entry:main /cetcompatstrict %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CETCOMPATSTRICT %s
+CETCOMPATSTRICT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETCOMPATSTRICT %s
+# RUN: lld-link /out:%t.exe /entry:main /cetcompatstrict:no %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETCOMPATSTRICT %s
+NONCETCOMPATSTRICT-NOT: IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE
+
+# RUN: lld-link /out:%t.exe /entry:main /cetipvalidationrelaxed %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CETCOMPATSTIPVALIDATIONRELAXED %s
+CETCOMPATSTIPVALIDATIONRELAXED: IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETCOMPATSTIPVALIDATIONRELAXED %s
+# RUN: lld-link /out:%t.exe /entry:main /cetipvalidationrelaxed:no %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETCOMPATSTIPVALIDATIONRELAXED %s
+NONCETCOMPATSTIPVALIDATIONRELAXED-NOT: IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE
+
+# RUN: lld-link /out:%t.exe /entry:main /cetdynamicapisinproc %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=CETDYNAMICAPISINPROC %s
+CETDYNAMICAPISINPROC: IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETDYNAMICAPISINPROC %s
+# RUN: lld-link /out:%t.exe /entry:main /cetdynamicapisinproc:no %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONCETDYNAMICAPISINPROC %s
+NONCETDYNAMICAPISINPROC-NOT: IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY
+
+# RUN: lld-link /out:%t.exe /entry:main /hotpatchcompatible %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=HOTPATCHCOMPATIBLE %s
+HOTPATCHCOMPATIBLE: IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE
+
+# RUN: lld-link /out:%t.exe /entry:main %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONHOTPATCHCOMPATIBLE %s
+# RUN: lld-link /out:%t.exe /entry:main /hotpatchcompatible:no %t.obj
+# RUN: llvm-readobj --coff-debug-directory %t.exe | FileCheck -check-prefix=NONHOTPATCHCOMPATIBLE %s
+NONHOTPATCHCOMPATIBLE-NOT: IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE
+
 # RUN: lld-link /out:%t.exe /entry:main /swaprun:CD %t.obj
 # RUN: llvm-readobj --file-headers %t.exe | FileCheck -check-prefix=SWAPCD %s
 # RUN: lld-link /out:%t.exe /entry:main /swaprun:cd,net %t.obj
diff --git a/llvm/include/llvm/BinaryFormat/COFF.h b/llvm/include/llvm/BinaryFormat/COFF.h
index f3b5d5e3f23c6..e06fc39b5de23 100644
--- a/llvm/include/llvm/BinaryFormat/COFF.h
+++ b/llvm/include/llvm/BinaryFormat/COFF.h
@@ -694,7 +694,22 @@ enum DLLCharacteristics : unsigned {
 
 enum ExtendedDLLCharacteristics : unsigned {
   /// Image is CET compatible
-  IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT = 0x0001
+  IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT = 0x0001,
+  /// Image is CET compatible in strict mode
+  IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE = 0x0002,
+  /// Image is CET compatible in such a way that context IP validation is relaxed
+  IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE = 0x0004,
+  /// Image is CET compatible in such a way that the use of
+  /// dynamic APIs is restricted to processes only
+  IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY = 0x0008,
+  /// Reserved for future use. Not used by MSVC link.exe
+  IMAGE_DLL_CHARACTERISTICS_EX_CET_RESERVED_1 = 0x0010,
+  /// Reserved for future use. Not used by MSVC link.exe
+  IMAGE_DLL_CHARACTERISTICS_EX_CET_RESERVED_2 = 0x0020,
+  /// Image is CFI compatible.
+  IMAGE_DLL_CHARACTERISTICS_EX_FORWARD_CFI_COMPAT = 0x0040,
+  /// Image is hotpatch compatible.
+  IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE = 0x0080,
 };
 
 enum DebugType : unsigned {
diff --git a/llvm/test/tools/llvm-readobj/COFF/cetcompatstrict.test b/llvm/test/tools/llvm-readobj/COFF/cetcompatstrict.test
new file mode 100644
index 0000000000000..9807bfe5686ee
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/cetcompatstrict.test
@@ -0,0 +1,16 @@
+# To regenerate has-cetstrict.exe
+# $ echo int main() { return 0; } > has-cetstrict.c
+# $ cl has-cetstrict.c /link /cetcompatstrict
+RUN: llvm-readobj --coff-debug-directory %p/Inputs/has-cetstrict.exe | FileCheck %s
+
+CHECK:  DebugEntry {
+CHECK:    Characteristics: 0x0
+CHECK:    Type: ExtendedDLLCharacteristics (0x14)
+CHECK:    ExtendedCharacteristics [ (0x2)
+CHECK:      IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE (0x2)
+CHECK:    ]
+CHECK:    RawData (
+CHECK:      0000: 02000000                             |....|
+CHECK:    )
+CHECK:  }
+
diff --git a/llvm/test/tools/llvm-readobj/COFF/cetdynamicapisinproc.test b/llvm/test/tools/llvm-readobj/COFF/cetdynamicapisinproc.test
new file mode 100644
index 0000000000000..18b3ec70177cb
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/cetdynamicapisinproc.test
@@ -0,0 +1,16 @@
+# To regenerate has-cetdynamicapisinproc.exe
+# $ echo int main() { return 0; } > has-cetdynamicapisinproc.c
+# $ cl has-cetdynamicapisinproc.c /link /cetdynamicapisinproc
+RUN: llvm-readobj --coff-debug-directory %p/Inputs/has-cetdynamicapisinproc.exe | FileCheck %s
+
+CHECK:  DebugEntry {
+CHECK:    Characteristics: 0x0
+CHECK:    Type: ExtendedDLLCharacteristics (0x14)
+CHECK:    ExtendedCharacteristics [ (0x8)
+CHECK:      IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY (0x8)
+CHECK:    ]
+CHECK:    RawData (
+CHECK:      0000: 08000000                             |....|
+CHECK:    )
+CHECK:  }
+
diff --git a/llvm/test/tools/llvm-readobj/COFF/cetipvalidationrelaxed.test b/llvm/test/tools/llvm-readobj/COFF/cetipvalidationrelaxed.test
new file mode 100644
index 0000000000000..25cf1db3464f7
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/cetipvalidationrelaxed.test
@@ -0,0 +1,16 @@
+# To regenerate has-cetipvalidationrelaxed.exe
+# $ echo int main() { return 0; } > has-cetipvalidationrelaxed.c
+# $ cl has-cetipvalidationrelaxed.c /link /cetipvalidationrelaxed
+RUN: llvm-readobj --coff-debug-directory %p/Inputs/has-cetipvalidationrelaxed.exe | FileCheck %s
+
+CHECK:  DebugEntry {
+CHECK:    Characteristics: 0x0
+CHECK:    Type: ExtendedDLLCharacteristics (0x14)
+CHECK:    ExtendedCharacteristics [ (0x4)
+CHECK:      IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE (0x4)
+CHECK:    ]
+CHECK:    RawData (
+CHECK:      0000: 04000000                             |....|
+CHECK:    )
+CHECK:  }
+
diff --git a/llvm/test/tools/llvm-readobj/COFF/hotpatchcompatible.test b/llvm/test/tools/llvm-readobj/COFF/hotpatchcompatible.test
new file mode 100644
index 0000000000000..87208d24f9fee
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/COFF/hotpatchcompatible.test
@@ -0,0 +1,16 @@
+# To regenerate has-hotpatchcompatible.exe
+# $ echo int main() { return 0; } > has-hotpatchcompatible.c
+# $ cl has-hotpatchcompatible.c /link /hotpatchcompatible
+RUN: llvm-readobj --coff-debug-directory %p/Inputs/has-hotpatchcompatible.exe | FileCheck %s
+
+CHECK:  DebugEntry {
+CHECK:    Characteristics: 0x0
+CHECK:    Type: ExtendedDLLCharacteristics (0x14)
+CHECK:    ExtendedCharacteristics [ (0x80)
+CHECK:      IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE (0x80)
+CHECK:    ]
+CHECK:    RawData (
+CHECK:      0000: 80000000                             |....|
+CHECK:    )
+CHECK:  }
+
diff --git a/llvm/tools/llvm-readobj/COFFDumper.cpp b/llvm/tools/llvm-readobj/COFFDumper.cpp
index dce8e60bda1ef..2f158e1bbe781 100644
--- a/llvm/tools/llvm-readobj/COFFDumper.cpp
+++ b/llvm/tools/llvm-readobj/COFFDumper.cpp
@@ -414,7 +414,14 @@ const EnumEntry<COFF::DLLCharacteristics> PEDLLCharacteristics[] = {
 
 static const EnumEntry<COFF::ExtendedDLLCharacteristics>
     PEExtendedDLLCharacteristics[] = {
-        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT                                ),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_COMPAT_STRICT_MODE                    ),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_SET_CONTEXT_IP_VALIDATION_RELAXED_MODE),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_DYNAMIC_APIS_ALLOW_IN_PROC_ONLY       ),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_RESERVED_1                            ),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_CET_RESERVED_2                            ),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_FORWARD_CFI_COMPAT                        ),
+        LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_DLL_CHARACTERISTICS_EX_HOTPATCH_COMPATIBLE                       ),
 };
 
 static const EnumEntry<COFF::SectionCharacteristics>

``````````

</details>


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


More information about the llvm-commits mailing list