[lld] [LLD][COFF] Support /DEPENDENTLOADFLAGS[:flags] (PR #71537)

Aleksei Nurmukhametov via llvm-commits llvm-commits at lists.llvm.org
Tue Nov 7 09:11:04 PST 2023


https://github.com/nurmukhametov updated https://github.com/llvm/llvm-project/pull/71537

>From 9df498d635a534d1671bcc22a2334973b506d25a Mon Sep 17 00:00:00 2001
From: "Nurmukhametov, Aleksei" <aleksei.nurmukhametov at intel.com>
Date: Fri, 3 Nov 2023 05:37:25 -0700
Subject: [PATCH] [LLD][COFF] Support /DEPENDENTLOADFLAGS[:flags]

---
 lld/COFF/Config.h                   |  1 +
 lld/COFF/Driver.cpp                 |  5 +++++
 lld/COFF/Driver.h                   |  3 +++
 lld/COFF/DriverUtils.cpp            | 13 ++++++++++++
 lld/COFF/Options.td                 |  3 +++
 lld/COFF/Writer.cpp                 | 20 ++++++++++++-------
 lld/test/COFF/dependentflags.test   | 29 +++++++++++++++++++++++++++
 lld/test/COFF/deploadflag-cfg-x64.s | 31 +++++++++++++++++++++++++++++
 8 files changed, 98 insertions(+), 7 deletions(-)
 create mode 100644 lld/test/COFF/dependentflags.test
 create mode 100644 lld/test/COFF/deploadflag-cfg-x64.s

diff --git a/lld/COFF/Config.h b/lld/COFF/Config.h
index 1c338cc63fa87d2..bee6dc3ec3caea4 100644
--- a/lld/COFF/Config.h
+++ b/lld/COFF/Config.h
@@ -287,6 +287,7 @@ struct Configuration {
   uint32_t timestamp = 0;
   uint32_t functionPadMin = 0;
   uint32_t timeTraceGranularity = 0;
+  uint16_t dependentLoadFlags = 0;
   bool dynamicBase = true;
   bool allowBind = true;
   bool cetCompat = false;
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index b2d0edd8cb2600e..bbbaba194e83e43 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2179,6 +2179,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
   for (auto *arg : args.filtered(OPT_functionpadmin, OPT_functionpadmin_opt))
     parseFunctionPadMin(arg);
 
+  // Handle /dependentloadflag
+  for (auto *arg :
+       args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt))
+    parseDependentLoadFlags(arg);
+
   if (tar) {
     llvm::TimeTraceScope timeScope("Reproducer: response file");
     tar->append("response.txt",
diff --git a/lld/COFF/Driver.h b/lld/COFF/Driver.h
index 549407539cdde9b..fa54de05befb580 100644
--- a/lld/COFF/Driver.h
+++ b/lld/COFF/Driver.h
@@ -233,6 +233,9 @@ class LinkerDriver {
   // Parses a string in the form of "[:<integer>]"
   void parseFunctionPadMin(llvm::opt::Arg *a);
 
+  // Parses a string in the form of "[:<integer>]"
+  void parseDependentLoadFlags(llvm::opt::Arg *a);
+
   // Parses a string in the form of "EMBED[,=<integer>]|NO".
   void parseManifest(StringRef arg);
 
diff --git a/lld/COFF/DriverUtils.cpp b/lld/COFF/DriverUtils.cpp
index 583f6af070b6258..ac817b44b5926ba 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -265,6 +265,19 @@ void LinkerDriver::parseFunctionPadMin(llvm::opt::Arg *a) {
   }
 }
 
+// Parses /dependentloadflag option argument.
+void LinkerDriver::parseDependentLoadFlags(llvm::opt::Arg *a) {
+  StringRef arg = a->getNumValues() ? a->getValue() : "";
+  if (!arg.empty()) {
+    if (arg.getAsInteger(0, ctx.config.dependentLoadFlags))
+      error("/dependentloadflag: invalid argument: " + arg);
+    return;
+  }
+  // MSVC linker reports error "no argument specified", although MSDN describes
+  // argument as optional.
+  error("no argument specified with option '/dependentloadflag'");
+}
+
 // Parses a string in the form of "EMBED[,=<integer>]|NO".
 // Results are directly written to
 // Config.
diff --git a/lld/COFF/Options.td b/lld/COFF/Options.td
index 977657a433dc581..abee6602726892d 100644
--- a/lld/COFF/Options.td
+++ b/lld/COFF/Options.td
@@ -56,6 +56,9 @@ def filealign : P<"filealign", "Section alignment in the output file">;
 def functionpadmin : F<"functionpadmin">;
 def functionpadmin_opt : P<"functionpadmin",
     "Prepares an image for hotpatching">;
+def dependentloadflag : F<"dependentloadflag">;
+def dependentloadflag_opt : P<"dependentloadflag",
+    "Sets the default load flags used to resolve the statically linked imports of a module">;
 def guard   : P<"guard", "Control flow guard">;
 def heap    : P<"heap", "Size of the heap">;
 def ignore : P<"ignore", "Specify warning codes to ignore">;
diff --git a/lld/COFF/Writer.cpp b/lld/COFF/Writer.cpp
index 960328d686852a3..218a4f336fedc6f 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -264,7 +264,8 @@ class Writer {
 
   uint32_t getSizeOfInitializedData();
 
-  void checkLoadConfig();
+  void prepareLoadConfig();
+  template <typename T> void prepareLoadConfig(T *loadConfig);
   template <typename T> void checkLoadConfigGuardData(const T *loadConfig);
 
   std::unique_ptr<FileOutputBuffer> &buffer;
@@ -696,7 +697,7 @@ void Writer::run() {
       writeHeader<pe32_header>();
     }
     writeSections();
-    checkLoadConfig();
+    prepareLoadConfig();
     sortExceptionTable();
 
     // Fix up the alignment in the TLS Directory's characteristic field,
@@ -2256,7 +2257,7 @@ void Writer::fixTlsAlignment() {
   }
 }
 
-void Writer::checkLoadConfig() {
+void Writer::prepareLoadConfig() {
   Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
   auto *b = cast_if_present<DefinedRegular>(sym);
   if (!b) {
@@ -2280,11 +2281,16 @@ void Writer::checkLoadConfig() {
          Twine(expectedAlign) + " bytes)");
 
   if (ctx.config.is64())
-    checkLoadConfigGuardData(
-        reinterpret_cast<const coff_load_configuration64 *>(symBuf));
+    prepareLoadConfig(reinterpret_cast<coff_load_configuration64 *>(symBuf));
   else
-    checkLoadConfigGuardData(
-        reinterpret_cast<const coff_load_configuration32 *>(symBuf));
+    prepareLoadConfig(reinterpret_cast<coff_load_configuration32 *>(symBuf));
+}
+
+template <typename T> void Writer::prepareLoadConfig(T *loadConfig) {
+  if (ctx.config.dependentLoadFlags)
+    loadConfig->DependentLoadFlags = ctx.config.dependentLoadFlags;
+
+  checkLoadConfigGuardData(loadConfig);
 }
 
 template <typename T>
diff --git a/lld/test/COFF/dependentflags.test b/lld/test/COFF/dependentflags.test
new file mode 100644
index 000000000000000..70f48fa88d2d55a
--- /dev/null
+++ b/lld/test/COFF/dependentflags.test
@@ -0,0 +1,29 @@
+// ---- precomp-a.obj - x86_64, hotpatch
+RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %S/Inputs/loadconfig-cfg-x64.s -o %t.ldcfg.obj
+
+RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force
+RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix BASE
+
+RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800
+RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800
+
+// ---- Many arguments
+RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x400 /dependentloadflag:0x800
+RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800
+
+RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800 /dependentloadflag:0x400
+RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400
+
+RUN: not lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag 2>&1 | FileCheck %s --check-prefix FAIL-NOARG
+RUN: not lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:zz 2>&1 | FileCheck %s --check-prefix FAIL
+RUN: not lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0xf0000 2>&1 | FileCheck %s --check-prefix FAIL-RANGE
+
+
+BASE: DependentLoadFlags: 0x0
+FLAGS-800: DependentLoadFlags: 0x800
+FLAGS-400: DependentLoadFlags: 0x400
+
+FAIL: lld-link: error: /dependentloadflag: invalid argument: zz
+FAIL-RANGE: lld-link: error: /dependentloadflag: invalid argument: 0xf0000
+FAIL-NOARG: lld-link: error: no argument specified with option '/dependentloadflag'
+
diff --git a/lld/test/COFF/deploadflag-cfg-x64.s b/lld/test/COFF/deploadflag-cfg-x64.s
new file mode 100644
index 000000000000000..4d4712c3c3d784c
--- /dev/null
+++ b/lld/test/COFF/deploadflag-cfg-x64.s
@@ -0,0 +1,31 @@
+# RUN: llvm-mc -triple x86_64-windows-msvc -filetype=obj %s -o %t.ldcfg.obj
+
+# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force
+# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400
+
+# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800
+# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-800
+
+# MSVC linker does not rewrite non-zero value of dependentloadflag in _load_config_used with zero
+# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x0
+# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400
+
+# RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800 /dependentloadflag:0x0
+# RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS-400
+
+# FLAGS-800: DependentLoadFlags: 0x800
+# FLAGS-400: DependentLoadFlags: 0x400
+
+        .section .rdata,"dr"
+.globl _load_config_used
+_load_config_used:
+        .long 256
+        .fill 74, 1, 0
+        .byte 0x00
+        .byte 0x40
+        .fill 48, 1, 0
+        .quad __guard_fids_table
+        .quad __guard_fids_count
+        .long __guard_flags
+        .fill 128, 1, 0
+



More information about the llvm-commits mailing list