Possible bug in binutils for MinGW-w64 related to linking weak symbols

Johannes Khoshnazar-Thoma johannes@johannesthoma.com
Thu Mar 19 11:01:18 GMT 2026


Hi Jan / List,

Thanks for your fast response, comments inline.

Am 19.03.26 um 09:31 schrieb Jan Beulich:
> On 18.03.2026 17:24, Johannes Khoshnazar-Thoma wrote:
>> Dear binutils developers,
>>
>> (note that I first posted this to the mingw-w64 mailing list:
>>
>> https://www.mail-archive.com/mingw-w64-public@lists.sourceforge.net/msg26192.html
>> )
>>
>> When compiling the Linux kernel with MinGW-w64,
> Why would you even try to build the Linux kernel (or any Linux binary) with
> other than a compiler targeting Linux?
Because we want to run Linux drivers as native Windows drivers. We already
did that for DRBD, but in WinDRBD the parts of the kernel needed by
DRBD are copiied out of the kernel (or reimplemented) which is not a good
solution from an engineering point of view. The kernel already loads as a
native Windows driver and boots until where it would exec init. This means
that primitives like spinlocks, threads, memory allocation, scheduling, ...
already work. The next step would be to get device mapper working
which would allow people to run lvm natively on a Windows host. Note
that this is not WSL2: WSL2 is a virtual machine, you can run Linux userland
but not drivers. Same for cygwin which is a POSIX API for Windows.

More thoughts on this Linux drivers on Windows project:

https://jtsoft.at/linux-drivers-for-windows/

WinDRBD project:

https://github.com/LINBIT/windrbd
>> I came across something
>> that looks like a linker (or maybe compiler) bug.
>>
>> When compiling and linking those 2 C files:
>>
>> // foo.c:
>> #include "foo.h"
>>
>> int __attribute__((weak)) foo(void)
>> {
>>       return 42;
>> }
>>
>> int __attribute__((weak)) bar(void)
>> {
>>       return 69;
>> }
>>
>> // foobar.c:
>> #include "foo.h"
>> #include <stdio.h>
>>
>> int main(void)
>> {
>>       printf("foo is %d\n", foo());
>>       printf("bar is %d\n", bar());
>> }
>>
>> // header foo.h is:
>> int foo(void);
>> int __attribute__((weak)) bar(void);
>>
>> the foo symbol is not defined when linking. The error
>> message is:
>>
>> /usr/lib/gcc/i686-w64-mingw32/14.2.1/../../../../i686-w64-mingw32/bin/ld:
>> foobar.o:foobar.c:(.text+0x4b): undefined reference to `foo'
>>       collect2: error: ld returned 1 exit status
>>       make: *** [Makefile:4: foobar] Error 1
> And that's when linking in both foobar.o and foo.o? The latter ought to
> provide a definition of foo(). The above looks like it would be the
> expected behavior when linking foobar.o alone into an executable.
Yes of course linking both object files together. bar is linked correctly
while foo is not.
>> The difference is that bar is declared weak also in the foo.h
>> header file while foo is not. The objdump of the foobar.o file
>> lists a (suspicious) entry:
>>
>>       [ 17](sec -1)(fl 0x00)(ty    0)(scl   2) (nx 0) 0x00000000 .weak._bar._main
>>
>> for bar but not for foo. This might be a hint for what is going wrong.
>>
>> I've put the reproducer project on github for your convenience:
>>
>> https://github.com/johannesthoma/mingw-weaktest.git
>>
>> Note that with a (for example) Linux gcc, this undefined reference does not
>> happen. It also works with LLVM clang for MinGW.
>>
>> So, my questions are:
>>
>>     * is this a real bug? Or is it just a different point of view onto how weak
>>       symbols are handled?
> I think it's a COFF vs ELF difference, but as per above some aspects
> are still unclear, so things may be different in the end.
We had that discussion on the mingw list already, but in my opinion
both foo and bar are properly defined, so not being able to link foo
looks like a bug to me. It works with clang/llvm.

Best regards,

- Johannes


More information about the Binutils mailing list