Possible bug in binutils for MinGW-w64 related to linking weak symbols
Jan Beulich
jbeulich@suse.com
Thu Mar 19 13:37:47 GMT 2026
On 19.03.2026 12:01, Johannes Khoshnazar-Thoma wrote:
> Am 19.03.26 um 09:31 schrieb Jan Beulich:
>> On 18.03.2026 17:24, Johannes Khoshnazar-Thoma wrote:
>>> 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.
Looks like I didn't pay close enough attention to ...
>>> 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
... the symbol name here. I can see code in gas responsible for setting up
such symbols. I'm unaware where the linker would consume them. Yet it seems
pretty clear that for this the declarations have to be marked "weak", too.
For weak-ness to be properly handled, that is. I agree ...
>>> 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.
... here, yet I can only assume that there's an issue with the code consuming
those .weak.* symbols, wherever that lives.
Jan
More information about the Binutils
mailing list