-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[LLD] [COFF] Print a warning when using /dependentloadflag without load config #117400
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
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
|
alvinhochun
left a comment
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_usedis being set, and given thatWriter::prepareLoadConfigalready 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
/dependentloadflagflag 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
| 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_usedexists.
Good point, added.
And to be really clear, ideally that test should have the
_load_config_usedsymbol 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.objinto 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
mstorsjo
left a comment
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!
alvinhochun
left a comment
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