[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