-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[LLD] [COFF] Print a warning when using /dependentloadflag without load config #117400
Conversation
@llvm/pr-subscribers-lld-coff @llvm/pr-subscribers-platform-windows Author: Mateusz Mikuła (mati865) ChangesFull diff: https://github.com/llvm/llvm-project/pull/117400.diff 2 Files Affected:
diff --git a/lld/COFF/Driver.cpp b/lld/COFF/Driver.cpp
index a0bff69c6302a2..8fe61d322cbec0 100644
--- a/lld/COFF/Driver.cpp
+++ b/lld/COFF/Driver.cpp
@@ -2307,8 +2307,11 @@ void LinkerDriver::linkerMain(ArrayRef<const char *> argsArr) {
// Handle /dependentloadflag
for (auto *arg :
- args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt))
+ args.filtered(OPT_dependentloadflag, OPT_dependentloadflag_opt)) {
parseDependentLoadFlags(arg);
+ if (!ctx.symtab.findUnderscore("_load_config_used"))
+ warn("_load_config_used not found, /delayloadflag will have no effect");
+ }
if (tar) {
llvm::TimeTraceScope timeScope("Reproducer: response file");
diff --git a/lld/test/COFF/dependentflags.test b/lld/test/COFF/dependentflags.test
index 3e90511591c75e..620e65ae0ff4f3 100644
--- a/lld/test/COFF/dependentflags.test
+++ b/lld/test/COFF/dependentflags.test
@@ -20,6 +20,7 @@ RUN: not lld-link %S/Inputs/precomp-a.obj %t.ldcfg.obj /out:%t.exe /nodefaultlib
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
+RUN: lld-link %S/Inputs/precomp-a.obj /out:%t.exe /nodefaultlib /force /dependentloadflag:0x800 2>&1 | FileCheck %s --check-prefix WARN-NOBASE
BASE: DependentLoadFlags: 0x0
FLAGS-800: DependentLoadFlags: 0x800
@@ -29,3 +30,4 @@ FAIL: lld-link: error: /dependentloadflag: invalid argument: zz
FAIL-RANGE: lld-link: error: /dependentloadflag: invalid argument: 0xf0000
FAIL-NOARG: lld-link: error: /dependentloadflag: no argument specified
+WARN-NOBASE: lld-link: warning: _load_config_used not found, /delayloadflag will have no effect
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should also be a test to make sure
lld/COFF/Driver.cpp
Outdated
parseDependentLoadFlags(arg); | ||
if (!ctx.symtab.findUnderscore("_load_config_used")) | ||
warn("_load_config_used not found, /delayloadflag will have no effect"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it right to check for the symbol so early? I thought at this point the objects/libraries haven't even been loaded yet so the symbol will always be missing.
I think the check should be added here instead:
llvm-project/lld/COFF/Writer.cpp
Lines 2604 to 2611 in 3a31427
void Writer::prepareLoadConfig() { | |
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; | |
} |
It can probably just check for a non-zero value, like in
llvm-project/lld/COFF/Writer.cpp
Lines 2634 to 2635 in 3a31427
if (ctx.config.dependentLoadFlags) | |
loadConfig->DependentLoadFlags = ctx.config.dependentLoadFlags; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had started there, but judging by other uses of ctx.symtab
I figured the driver might be the right place to put it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My preference would be to put the check closer to where the field in _load_config_used
is being set, and given that Writer::prepareLoadConfig
already does other checks on _load_config_used
, it just seems to me to be the more logical place to add the check.
(I was also a bit concerned that resolving the symbol earlier than before may subtly change the behaviour and output of LLD, but I guess there isn't really much to break here.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition, the current code would emit one warning per every /dependentloadflag
flag specified (when multiple are passed, only the last one would take effect).
Also, I just noticed the typo – the warning message refers to "/delayloadflag" instead of /dependentloadflag
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My preference would be to put the check closer to where the field in
_load_config_used
is being set, and given thatWriter::prepareLoadConfig
already does other checks on_load_config_used
, it just seems to me to be the more logical place to add the check.
Sure, I don't have a strong option here for either approach.
In addition, the current code would emit one warning per every
/dependentloadflag
flag specified (when multiple are passed, only the last one would take effect).
Oh, that's right. I'll see what I can do about it.
Also, I just noticed the typo – the warning message refers to "/delayloadflag" instead of
/dependentloadflag
.
Dang, good catch!
lld/test/COFF/dependentflags.test
Outdated
@@ -29,3 +30,4 @@ FAIL: lld-link: error: /dependentloadflag: invalid argument: zz | |||
FAIL-RANGE: lld-link: error: /dependentloadflag: invalid argument: 0xf0000 | |||
FAIL-NOARG: lld-link: error: /dependentloadflag: no argument specified | |||
|
|||
WARN-NOBASE: lld-link: warning: _load_config_used not found, /delayloadflag will have no effect |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test to check that no warnings are emitted if _load_config_used
exists.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And to be really clear, ideally that test should have the _load_config_used
symbol in a static library, so it’s not explicitly referenced or pulled in, other than lld doing it implicitly at the end.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a test to check that no warnings are emitted if
_load_config_used
exists.
Good point, added.
And to be really clear, ideally that test should have the
_load_config_used
symbol in a static library, so it’s not explicitly referenced or pulled in, other than lld doing it implicitly at the end.
Just to confirm. It'd be enough to turn ldcfg.obj
into a static library and directly pass that library to LLD?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to confirm. It'd be enough to turn
ldcfg.obj
into a static library and directly pass that library to LLD?
Yes, that’s right, thanks!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, I also felt a little skeptic that this would be enough, as we're only scanning the files that are mentioned directly on the command line:
https://github.com/llvm/llvm-project/blob/llvmorg-19.1.4/lld/COFF/Driver.cpp#L2134-L2169
As technically, the _load_config_used
struct can be brought in at a later stage as well, here: https://github.com/llvm/llvm-project/blob/llvmorg-19.1.4/lld/COFF/Driver.cpp#L2397-L2448
I tried to adjust the testcase even further, so that we have two files on the command line - an entry point object, and a library. The entry point object references the library, and the object in the library has got an embedded /defaultlib:
directive, pointing to another library, which has got the _load_config_used
struct. But even then, the warning works as expected - not warning for this. See mstorsjo@lld-dependentloadflag-warn for my attempt at this.
I also tested with real MSVC libraries (where there's usually a somewhat deep nested structure of /defaultlib:
directives between msvcrt/ucrt/vcruntime etc), but there, the _load_config_used
is also in a toplevel library, and linking a regular hello world, with /dependentloadflag:0
, doesn't produce any warning here.
So with that, I think this may cover enough of the practical cases and keeps the code simple. Or what do you think @alvinhochun?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for testing this!
Should I cherry-pick 1a5c668 to this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure - what does @alvinhochun think? It makes the testcase more complicated, but also closer to the real world scenario.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test in that commit RUN: lld-link %t.entry.obj /libpath:%t-libdir %t.ldcfg-defaultlib.lib /out:%t.exe /entry:entry /subsystem:console /dependentloadflag:0x801 2>&1 | FileCheck %s --allow-empty --check-prefix NO-WARN
does not have /nodefaultlib
, would that not pull in the default CRT libs and invalidate the test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I needed to remove the /nodefaultlib
to make it actually do the thing I wanted to test, having %t.ldcfg-defaultlib.lib
contain a /defaultlib:
directive, that pulls in another library - with /nodefaultlib
it would ignore those.
Linking without /nodefaultlib
doesn't pull in the default CRT libs automatically, only if the object files tells it to. In this case, %S/Inputs/precomp-a.obj
contains such directives, but I switched that to a different object file for the entry, which doesn't reference LIBCMT.LIB
and such.
1e6a534
to
defcde6
Compare
Noticed |
Good catch, yes I guess that ideally should be fixed. |
defcde6
to
9704ea0
Compare
FWIW I looked at the assembly, and immediately it became obvious that I should leave it to someone who actually knows what's going on in there. |
Sorry for the late reply. I also want to point out that llvm-project/lld/COFF/Writer.cpp Lines 2634 to 2635 in 3a31427
only sets the DependentLoadFlags field of _load_config_used if it is set to a non-zero value. This means passing /dependentloadflag:0 is effectively a no-op, so that if the _load_config_used struct already has a non-zero value set in that field, LLD will not clear the flag. I am not sure if this is intended – if it is, then setting it to 0 should probably not give the warning. (CC @nurmukhametov @tru @aganea from #71537)
One more note that is not strictly related to this PR: Before setting the field, there seems to be no checks to make sure the
(It probably just needs a |
No problem.
I don't mind either way, I'm going to change it.
I think it has nothing to do with this PR unless I missed something obvious. I'm not going to look into it.
Likewise, I'm not going to look into it.
I have tried that and several other ways I could find, but the warning wouldn't go away. |
It looks intended to match the behavior of the MSVC linker. See here: https://github.com/nurmukhametov/llvm-project/blob/e72c949c15208ba3dd53a9cebfee02734965a678/lld/test/COFF/deploadflag-cfg-x64.s#L11 |
9704ea0
to
c69accc
Compare
✅ With the latest revision this PR passed the C/C++ code formatter. |
c69accc
to
5a75227
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This LGTM now, and seems to be in line with what @alvinhochun requested. If there's no more comments, I'd merge this soon. Thanks for sticking to it!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, LGTM too.
@mati865 Can you uncheck the box in your github settings, to keep your account email secret? If I do a squash&merge (the only one allowed here), it sets an anonymized email for the resulting commit, see https://github.com/llvm/llvm-project/blob/main/.github/workflows/email-check.yaml#L34. |
@mstorsjo sure, done. BTW, thanks for reminding me to update my email address... |
As per request in #113814