Closed jschueller closed 1 month ago
@llvm/issue-subscribers-lld-elf
Author: Julien Schueller (jschueller)
This primarily seems to be a libstdc++ issue for this target.
In your case, if you compile the test source to an object file, and inspect it:
$ i686-w64-mingw32-g++ -c foo.cxx
$ i686-w64-mingw32-nm foo.o
00000000 b .bss
00000000 d .data
00000000 r .eh_frame
00000000 r .rdata
00000000 r .rdata$zzz
00000000 t .text
U _ZSt21ios_base_library_initv
00000000 T __Z3foov
U __ZNSt14basic_ofstreamIcSt11char_traitsIcEEC1EPKcSt13_Ios_Openmode
U __ZNSt14basic_ofstreamIcSt11char_traitsIcEED1Ev
0000000b r __ZNSt8__detail30__integer_to_chars_is_unsignedIjEE
0000000c r __ZNSt8__detail30__integer_to_chars_is_unsignedImEE
0000000d r __ZNSt8__detail30__integer_to_chars_is_unsignedIyEE
Note how the reference to _ZSt21ios_base_library_initv
only has one leading underscore, while the other ones have two. Normally, for this target, Itanium C++ ABI symbols would have two leading underscores - one as part of the Itanium name mangling itself, and one extra added as part of the i386/windows environment.
If we inspect the libraries that should provide it:
$ i686-w64-mingw32-nm /usr/i686-w64-mingw32/sys-root/mingw/lib/libstdc++.dll.a | grep _ZSt21ios_base_library_initv
00000000 T __ZSt21ios_base_library_initv
00000000 I __imp___ZSt21ios_base_library_initv
$ i686-w64-mingw32-nm /usr/i686-w64-mingw32/sys-root/mingw/lib/libstdc++.a | grep _ZSt21ios_base_library_initv
00000000 T __ZSt21ios_base_library_initv
If we have a look at /usr/i686-w64-mingw32/sys-root/mingw/include/c++/iostream
, we find this:
#if !(_GLIBCXX_USE_INIT_PRIORITY_ATTRIBUTE \
&& __has_attribute(__init_priority__))
static ios_base::Init __ioinit;
#elif defined(_GLIBCXX_SYMVER_GNU)
__extension__ __asm (".globl _ZSt21ios_base_library_initv");
#endif
(Also found here: https://github.com/gcc-mirror/gcc/blob/master/libstdc%2B%2B-v3/include/std/iostream#L78-L83)
Also looking at /usr/i686-w64-mingw32/sys-root/mingw/include/c++/i686-w64-mingw32/bits/c++config.h
, we have this:
#define _GLIBCXX_USE_INIT_PRIORITY_ATTRIBUTE 1
#define _GLIBCXX_SYMVER_GNU 1
So for this particular build configuration, it seems like libstdc++ would need to inject __USER_LABEL_PREFIX__
as a prefix in the __extension__ __asm
statement.
With the root issue clarified - GNU ld still manages to link this, while LLD errors out. I guess the deal is that there are no relocations against the symbol, I guess GNU ld feels that it's not an issue for the end result, and only errors out for references against undefined symbols, not undefined symbols in general.
I guess it would be possible to do such a change to LLD, but I'm not sure if that's really something we want to do here. The linker input is quite apparently incorrect...
thanks for the detailed explanation, indeed I could fix it using __USER_LABEL_PREFIX__
:
diff --git a/libstdc++-v3/include/std/iostream b/libstdc++-v3/include/std/iostream
index 0c6a2d8a4b3..6bfb7e25271 100644
--- a/libstdc++-v3/include/std/iostream
+++ b/libstdc++-v3/include/std/iostream
@@ -79,7 +79,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
&& __has_attribute(__init_priority__))
static ios_base::Init __ioinit;
#elif defined(_GLIBCXX_SYMVER_GNU)
- __extension__ __asm (".globl _ZSt21ios_base_library_initv");
+ #define XSTRINGIFY(X) STRINGIFY(X)
+ #define STRINGIFY(X) #X
+ __extension__ __asm (".globl " XSTRINGIFY(__USER_LABEL_PREFIX__) "_ZSt21ios_base_library_initv");
#endif
_GLIBCXX_END_NAMESPACE_VERSION
with this patch it links properly for both i686 & x86_64
compiling this code with gcc into a shared lib for mingw/i686 and linking with lld fails:
but it goes fine with x86_64-w64-mingw32-g++ also tried to force -lstdc++ versions used are gcc 14.1 / mingw 12.0, lld 18.1 to reproduce on archlinux (or fedora) install mingw-w64-gcc & lld, symlink /usr/i686-w64-mingw32/bin/ld.lld to /usr/bin/lld
/cc @mstorsjo since you seem interested in lld/mingw