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