[lld] [LLD][COFF] Support /DEPENDENTLOADFLAGS[:flags] (PR #71537)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Nov 7 06:00:43 PST 2023
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-lld
Author: Alexey Nurmukhametov (nurmukhametov)
<details>
<summary>Changes</summary>
This should fix https://github.com/llvm/llvm-project/issues/43935
---
Full diff: https://github.com/llvm/llvm-project/pull/71537.diff
7 Files Affected:
- (modified) lld/COFF/Config.h (+1)
- (modified) lld/COFF/Driver.cpp (+4)
- (modified) lld/COFF/Driver.h (+3)
- (modified) lld/COFF/DriverUtils.cpp (+12)
- (modified) lld/COFF/Options.td (+3)
- (modified) lld/COFF/Writer.cpp (+31)
- (added) lld/test/COFF/dependentflags.test (+28)
``````````diff
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..6563b45830e6ffd 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2179,6 +2179,10 @@ 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..510dd3c1ceb4bed 100644
--- a/lld/COFF/DriverUtils.cpp
+++ b/lld/COFF/DriverUtils.cpp
@@ -265,6 +265,18 @@ 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;
+ }
+ // No optional argument given. Default value is 0.
+ ctx.config.dependentLoadFlags = 0;
+}
+
// 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..eb26241d5229662 100644
--- a/lld/COFF/Writer.cpp
+++ b/lld/COFF/Writer.cpp
@@ -264,6 +264,9 @@ class Writer {
uint32_t getSizeOfInitializedData();
+ void changeLoadConfig();
+ template <typename T> void changeLoadConfigGuardData(T *loadConfig);
+
void checkLoadConfig();
template <typename T> void checkLoadConfigGuardData(const T *loadConfig);
@@ -696,6 +699,7 @@ void Writer::run() {
writeHeader<pe32_header>();
}
writeSections();
+ changeLoadConfig();
checkLoadConfig();
sortExceptionTable();
@@ -2256,6 +2260,33 @@ void Writer::fixTlsAlignment() {
}
}
+void Writer::changeLoadConfig() {
+ Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
+ auto *b = cast_if_present<DefinedRegular>(sym);
+ if (!b) {
+ if (ctx.config.guardCF != GuardCFLevel::Off)
+ warn("Control Flow Guard is enabled but '_load_config_used' is missing");
+ return;
+ }
+
+ OutputSection *sec = ctx.getOutputSection(b->getChunk());
+ uint8_t *buf = buffer->getBufferStart();
+ uint8_t *secBuf = buf + sec->getFileOff();
+ uint8_t *symBuf = secBuf + (b->getRVA() - sec->getRVA());
+ if (ctx.config.is64())
+ changeLoadConfigGuardData(
+ reinterpret_cast<coff_load_configuration64 *>(symBuf));
+ else
+ changeLoadConfigGuardData(
+ reinterpret_cast<coff_load_configuration32 *>(symBuf));
+}
+
+template <typename T>
+void Writer::changeLoadConfigGuardData(T *loadConfig) {
+ if (ctx.config.dependentLoadFlags)
+ loadConfig->DependentLoadFlags = ctx.config.dependentLoadFlags;
+}
+
void Writer::checkLoadConfig() {
Symbol *sym = ctx.symtab.findUnderscore("_load_config_used");
auto *b = cast_if_present<DefinedRegular>(sym);
diff --git a/lld/test/COFF/dependentflags.test b/lld/test/COFF/dependentflags.test
new file mode 100644
index 000000000000000..3507e098a06eb0c
--- /dev/null
+++ b/lld/test/COFF/dependentflags.test
@@ -0,0 +1,28 @@
+// ---- 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
+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
+
+// ---- Many arguments
+RUN: lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800 /dependentloadflag
+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 /dependentloadflag:0x800
+RUN: llvm-readobj --coff-load-config %t.exe | FileCheck %s --check-prefix FLAGS
+
+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: DependentLoadFlags: 0x800
+
+FAIL: lld-link: error: /dependentloadflag: invalid argument: zz
+FAIL-RANGE: lld-link: error: /dependentloadflag: invalid argument: 0xf0000
\ No newline at end of file
``````````
</details>
https://github.com/llvm/llvm-project/pull/71537
More information about the llvm-commits
mailing list