Possible bug in binutils for MinGW-w64 related to linking weak symbols
Fangrui Song
i@maskray.me
Fri Mar 20 04:12:37 GMT 2026
On Thu, Mar 19, 2026 at 4:31 PM Eric Botcazou <ebotcazou@libertysurf.fr> wrote:
>
> > True, but it works differently on the mingw-w64 target than on all others.
> > On a Linux target, the code compiles and links without problems. IMHO it
> > shouldn't change the semantics of __attribute__((weak))__ depending on
> > target architecture.
>
> "weak" is a pure ELF thing, so the argument does not sound very convincing
> when applied to it and another object file format.
>
> --
> Eric Botcazou
>
There is a distinction between weak definition and weak reference.
The linker should allow a regular reference from foobar.o to resolve
to a weak definition (simulated with IMAGE_SYM_CLASS_WEAK_EXTERNAL
IMAGE_SYM_UNDEFINED symbol with an IMAGE_SYM_CLASS_EXTERNAL
IMAGE_SYM_ABSOLUTE auxiliary symbol
https://maskray.me/blog/2021-04-25-weak-symbol#pecoff).
% make clean && make
rm -f *.o
rm -f foobar.exe
clang --target=i686-w64-mingw32 -c foo.c -o foo.o
clang --target=i686-w64-mingw32 -c foobar.c -o foobar.o
clang --target=i686-w64-mingw32 -fuse-ld=lld -nostdlib
-Wl,--entry,__start foo.o foobar.o -o foobar.exe
% make clean && make USE_GNU_LD=1
rm -f *.o
rm -f foobar.exe
clang --target=i686-w64-mingw32 -c foo.c -o foo.o
clang --target=i686-w64-mingw32 -c foobar.c -o foobar.o
clang --target=i686-w64-mingw32
--ld-path=/home/ray/Dev/binutils-gdb/out/mingw/ld/ld-new -nostdlib
-Wl,--entry,__start foo.o foobar.o -o foobar.exe
/home/ray/Dev/binutils-gdb/out/mingw/ld/ld-new:
foobar.o:foobar.c:(.text+0x7): undefined reference to `foo'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [Makefile:13: foobar.exe] Error 1
I don't have a mingw toolchain. I have made some changes to make the
example work without C stdlib
diff --git i/Makefile w/Makefile
index fd2e035..43a692b 100644
--- i/Makefile
+++ w/Makefile
@@ -1,8 +1,20 @@
-CC=i686-w64-mingw32-gcc
+CC=clang
+CFLAGS=--target=i686-w64-mingw32
-foobar: foo.o foobar.o
- $(CC) foo.o foobar.o -o $@
+# USE_GNU_LD=1 to use GNU ld instead of lld
+GNU_LD=/home/ray/Dev/binutils-gdb/out/mingw/ld/ld-new
+ifdef USE_GNU_LD
+LDFLAGS=--target=i686-w64-mingw32 --ld-path=$(GNU_LD) -nostdlib
-Wl,--entry,__start
+else
+LDFLAGS=--target=i686-w64-mingw32 -fuse-ld=lld -nostdlib -Wl,--entry,__start
+endif
+
+foobar.exe: foo.o foobar.o
+ $(CC) $(LDFLAGS) foo.o foobar.o -o $@
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c $< -o $@
clean:
rm -f *.o
- rm -f foobar
+ rm -f foobar.exe
diff --git i/foobar.c w/foobar.c
index 2b476a2..9c4c1b9 100644
--- i/foobar.c
+++ w/foobar.c
@@ -1,8 +1,8 @@
#include "foo.h"
-#include <stdio.h>
-int main(void)
+void _start(void)
{
- printf("foo is %d\n", foo());
- printf("bar is %d\n", bar());
+ int ret = foo() + bar();
+ (void)ret;
+ __builtin_trap();
}
More information about the Binutils
mailing list