Package: gcc-mingw-w64
Version: 21.2
Hi!
I've discovered that mingw-w64 GCC in Debian is configured without
linker plugin support:
$ x86_64-w64-mingw32-gcc -x c - -flto -fno-fat-lto-objects <<<'int
main() {}'
cc1: error: -fno-fat-lto-objects are supported only with linker plugin
This makes LTO unusable in many real-world cases. Consider the following
example:
$ grep . *.c
foo.c:int foo() {return 42;}
main.c:int main() {return foo();}
$ x86_64-w64-mingw32-gcc -flto -O2 foo.c main.c -c
$ x86_64-w64-mingw32-ar cr app.a main.o foo.o
$ x86_64-w64-mingw32-gcc -flto -O2 app.a
$ x86_64-w64-mingw32-objdump -d a.exe | grep '<main>:' -A 5
0000000000402c30 <main>:
402c30: 48 83 ec 28 sub $0x28,%rsp
402c34: e8 d7 e9 ff ff callq 401610 <__main>
402c39: 90 nop
402c3a: 48 83 c4 28 add $0x28,%rsp
402c3e: e9 0d e9 ff ff jmpq 401550 <foo> # 'foo' is
not inlined
Note that 'foo' is not inlined because the archived object files weren't
processed by LTO (they were processed by the linker as normal objects
because they are "fat" LTO objects, i.e. they contain both normal object
code and GCC IR).
$ x86_64-w64-mingw32-gcc -flto -O2 main.o foo.o
$ x86_64-w64-mingw32-objdump -d a.exe | grep '<main>:' -A 5
0000000000402c30 <main>:
402c30: 48 83 ec 28 sub $0x28,%rsp
402c34: e8 d7 e9 ff ff callq 401610 <__main>
402c39: b8 2a 00 00 00 mov $0x2a,%eax # Good, 'foo'
is inlined!
402c3e: 48 83 c4 28 add $0x28,%rsp
402c42: c3 retq
In this case, legacy LTO implementation was used: GCC driver looked at
the objects and called its 'lto-wrapper' helper. But it can't do that
with archives.
This misconfiguration is caused by the incorrect use of
'--with-plugin-ld' GCC configure option (or its strange behavior,
depending on how you look at it):
$ x86_64-w64-mingw32-gcc -v
Using built-in specs.
COLLECT_GCC=x86_64-w64-mingw32-gcc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-w64-mingw32/8.3-win32/lto-wrapper
Target: x86_64-w64-mingw32
Configured with: ../../src/configure --build=x86_64-linux-gnu
--prefix=/usr --includedir='/usr/include' --mandir='/usr/share/man'
--infodir='/usr/share/info' --sysconfdir=/etc --localstatedir=/var
--disable-silent-rules --libdir='/usr/lib/x86_64-linux-gnu'
--libexecdir='/usr/lib/x86_64-linux-gnu' --disable-maintainer-mode
--disable-dependency-tracking --prefix=/usr --enable-shared
--enable-static --disable-multilib --with-system-zlib
--libexecdir=/usr/lib --without-included-gettext --libdir=/usr/lib
--enable-libstdcxx-time=yes --with-tune=generic
--with-headers=/usr/x86_64-w64-mingw32/include
--enable-version-specific-runtime-libs --enable-fully-dynamic-string
--enable-libgomp --enable-languages=c,c++,fortran,objc,obj-c++,ada
--enable-lto --with-plugin-ld --enable-threads=win32
--program-suffix=-win32 --program-prefix=x86_64-w64-mingw32-
--target=x86_64-w64-mingw32 --with-as=/usr/bin/x86_64-w64-mingw32-as
--with-ld=/usr/bin/x86_64-w64-mingw32-ld --enable-libatomic
--enable-libstdcxx-filesystem-ts=yes
Thread model: win32
gcc version 8.3-win32 20190406 (GCC)
The problem is that "--with-plugin-ld" expects a linker path as the
value, but if it's not given, the value becomes 'yes' and is then tested
for plugin support, without much success (lookup "checking linker plugin
support" in
"https://buildd.debian.org/status/fetch.php?pkg=gcc-mingw-w64&arch=amd64&ver=21.2&stamp=1555227419&raw=0").
This option is actually not needed since there is no need to use an
"alternative" linker for plugins: the one that is passed with
"--with-ld" will do. I've checked manually that if I remove
"--with-plugin-ld" from the configuration of gcc-mingw-w64 source
package, the linker plugin support is detected properly.
Ubuntu packages are also affected by this problem. I've checked that
OpenSUSE Tumbleweed packages are not affected (they don't use
"--with-plugin-ld").
I suggest to remove "--with-plugin-ld" from GCC configuration options.
Thanks!
-Alexey