-
Notifications
You must be signed in to change notification settings - Fork 11.1k
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
LTO builds fail when dllimport functions are called locally #37453
Comments
Hopefully Peter who I cc'ed on this can take a look. It is the index-based computeDeadSymbols that is causing the issue for both regular and thin LTO. Disabling it via /mllvm:-compute-dead=false makes the issue go away. The problem is that LTO::run is getting 2 GlobalResolutions for foo, one prevailing from b.obj and one non-prevailing from a.obj. It processes the prevailing first and this line sets the GUID to prevailing:
When the non-prevailing a.obj copy is processed, it is overwritten with No. Peter - what should be happening here? Should we never reset to No after setting to Yes? |
The issue is that there are two separate symbols involved, which leads to there being two entries in GlobalResolutions for the same IR symbol: $ ~/src2/llvm-project/ra/bin/llvm-nm a.obj The same root cause was probably also causing this code: http://llvm-cs.pcc.me.uk/lib/LTO/LTO.cpp#858 to be run twice for the same symbol in the -flto case, causing an incorrect linkage to be set on the dllimport symbol (although I couldn't reproduce this myself). I'm not sure what the right fix is yet. |
lld has special handling to disregard the _imp prefix if necessary: llvm-mirror/lld@add5dd0#diff-e248c0b838e4ca91656fc436f8f5e9ac That even allows for a case of calling an _imp function directly without dllimport keywords. (yuck! but compat, I guess?) Should the LTO code do something similar? |
Indeed, the following patch fixes the issue: diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp
I can send a patch with test later today or tomorrow. |
Fix mailed in D49138, plus lld test in D49140. |
Thank you Teresa! This patch fixes all but one of the undefined symbols in the Firefox LTO build. I'll try to reduce the one remaining failure (may take some time) and file a new bug if it turns out to be unrelated. |
Fixed in r337762. |
Commit b963c0b fixed LTO compilation of cases where one translation unit is calling a function with the dllimport attribute, and another translation unit provides this function locally within the same linked module (i.e. not actually dllimported); see llvm#37453 or https://bugs.llvm.org/show_bug.cgi?id=38105 for full context. This was fixed by aliasing their GlobalResolution structs, for the __imp_ prefixed and non prefixed symbols. I believe this fix to be wrong. This patch reverts that fix, and fixes the same issue differently, within LLD instead. The fix assumed that one can treat the __imp_ prefixed and unprefixed symbols as equal, referencing SVN r240620 (d766653). However that referenced commit had mistaken how this logic works, which was corrected later in SVN r240622 (88e0f92); those symbols aren't direct aliases for each other - but if there's a need for the __imp_ prefixed one and the other one exists, the __imp_ prefixed one is created, as a pointer to the other one. However this fix only works if both translation units are compiled as LTO; if the caller is compiled as a regular object file and the callee is compiled as LTO, the fix fails, as the LTO compilation doesn't know that the unprefixed symbol is needed. The only level that knows of the potential relationship between the __imp_ prefixed and unprefixed symbol, across regular and bitcode object files, is LLD itself. Therefore, revert the original fix from b963c0b, and fix the issue differently - when concluding that we can fulfill an undefined symbol starting with __imp_, mark the corresponding non prefixed symbol as used in a regular object for the LTO compilation, to make sure that this non prefixed symbol exists after the LTO compilation, to let LLD do the fixup of the local import. Extend the testcase to test a regular object file calling an LTO object file, which previously failed. This change also fixes another issue; an object file can provide both unprefixed and prefixed versions of the same symbol, like this: void importedFunc(void) { } void (*__imp_importedFunc)(void) = importedFunc; That allows the function to be called both with and without dllimport markings. (The concept of automatically resolving a reference to __imp_func to a locally defined func only is done in MSVC style linkers, but not in GNU ld, therefore MinGW mode code often uses this construct.) Previously, the aliasing of global resolutions at the LTO level would trigger a failed assert with "Multiple prevailing defs are not allowed" for this case, as both importedFunc and __imp_importedFunc could be prevailing. Add a case to the existing LLD test case lto-imp-prefix.ll to test this as well. This change (together with previous change in 3ab6209) completes LLD to work with mingw-w64-crt files (the base glue code for a mingw-w64 toolchain) built with LTO.
…71376) Commit b963c0b fixed LTO compilation of cases where one translation unit is calling a function with the dllimport attribute, and another translation unit provides this function locally within the same linked module (i.e. not actually dllimported); see #37453 or https://bugs.llvm.org/show_bug.cgi?id=38105 for full context. This was fixed by aliasing their GlobalResolution structs, for the `__imp_` prefixed and non prefixed symbols. I believe this fix to be wrong. This patch reverts that fix, and fixes the same issue differently, within LLD instead. The fix assumed that one can treat the `__imp_` prefixed and unprefixed symbols as equal, referencing SVN r240620 (d766653). However that referenced commit had mistaken how this logic works, which was corrected later in SVN r240622 (88e0f92); those symbols aren't direct aliases for each other - but if there's a need for the `__imp_` prefixed one and the other one exists, the `__imp_` prefixed one is created, as a pointer to the other one. However this fix only works if both translation units are compiled as LTO; if the caller is compiled as a regular object file and the callee is compiled as LTO, the fix fails, as the LTO compilation doesn't know that the unprefixed symbol is needed. The only level that knows of the potential relationship between the `__imp_` prefixed and unprefixed symbol, across regular and bitcode object files, is LLD itself. Therefore, revert the original fix from b963c0b, and fix the issue differently - when concluding that we can fulfill an undefined symbol starting with `__imp_`, mark the corresponding non prefixed symbol as used in a regular object for the LTO compilation, to make sure that this non prefixed symbol exists after the LTO compilation, to let LLD do the fixup of the local import. Extend the testcase to test a regular object file calling an LTO object file, which previously failed. This change also fixes another issue; an object file can provide both unprefixed and prefixed versions of the same symbol, like this: void importedFunc(void) { } void (*__imp_importedFunc)(void) = importedFunc; That allows the function to be called both with and without dllimport markings. (The concept of automatically resolving a reference to `__imp_func` to a locally defined `func` only is done in MSVC style linkers, but not in GNU ld, therefore MinGW mode code often uses this construct.) Previously, the aliasing of global resolutions at the LTO level would trigger a failed assert with "Multiple prevailing defs are not allowed" for this case, as both `importedFunc` and `__imp_importedFunc` could be prevailing. Add a case to the existing LLD test case lto-imp-prefix.ll to test this as well. This change (together with previous change in 3ab6209) completes LLD to work with mingw-w64-crt files (the base glue code for a mingw-w64 toolchain) built with LTO.
Extended Description
When a function is declared dllimport but called directly (i.e. in the same binary), a non-LTO build will issue a warning but still succeed (same as MSVC). LTO and ThinLTO builds fail with linkage complaints.
This is preventing Firefox's use of LTO on Windows: https://bugzilla.mozilla.org/show_bug.cgi?id=1448976
clang version 7.0.0 (trunk 336407)
$ cat a.cpp
__declspec(dllimport) int foo();
int main() { return foo(); }
$ cat b.cpp
int foo() { return 42; }
$ cat test.sh
#!/bin/bash
rm -rf *.obj *.exe
clang-cl $FLAG -O2 -c a.cpp b.cpp
lld-link -nodefaultlib -entry:main a.obj b.obj
$ ./test.sh
lld-link.exe: warning: a.obj: locally defined symbol imported: ?foo@@yahxz (defined in b.obj) [LNK4217]
$ FLAG=-flto ./test.sh
Global is external, but doesn't have external or weak linkage!
i32 ()* @"?foo@@yahxz"
LLVM ERROR: Broken module found, compilation aborted!
$ FLAG=-flto=thin ./test.sh
lld-link.exe: error: undefined symbol: ?foo@@yahxz
The text was updated successfully, but these errors were encountered: