Bug 9687

Summary: Weak symbols not working on mingw32
Product: binutils Reporter: tcl_de
Component: gasAssignee: unassigned
Status: NEW ---    
Severity: normal CC: bug-binutils, christian.joensson, dave.korn.cygwin, mailing-list, xunxun1982
Priority: P2    
Version: 2.19   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:
Attachments: This is the original weak.o generated by gas
This is the modified weak.o (with IMAGE_WEAK_EXTERN_SEARCH_ALIAS)

Description tcl_de 2008-12-27 13:47:27 UTC
Using
>GNU assembler (GNU Binutils) 2.19
>Copyright 2007 Free Software Foundation, Inc.
>This program is free software; you may redistribute it under the terms of
>the GNU General Public License version 3 or later.
>This program has absolutely no warranty.
>This assembler was configured for a target of `mingw32'.
and corresponding GNU ld I get the following output running gcc 4.3 rev 142914:
>W:/WINDOWS/TMP/cc1R156y.o:main.c:(.text+0x17): undefined reference to `function'
>collect2: ld returned 1 exit status
when compiling the following to files:
================== main.c =================
extern void function();

int main()
{
    function();
	return 0;
}
================== weak.c =================
#include <stdio.h>

void __attribute__((weak)) function()
{
    printf("Hello from the weak function\n");
}

======== Asm code of weak.c after being processed by gcc ========
	.file	"weak.c"
	.section .rdata,"dr"
LC0:
	.ascii "Hello from the weak function\0"
	.text
	.weak	_function
	.def	_function;	.scl	2;	.type	32;	.endef
_function:
	pushl	%ebp
	movl	%esp, %ebp
	subl	$8, %esp
	movl	$LC0, (%esp)
	call	_puts
	leave
	ret
	.def	_puts;	.scl	2;	.type	32;	.endef
===================================================
This means as far as I can tell that either ld does not find the weak symbol or
that as does not correctly save the weak symbol in the PE File.
Comment 1 Danny Smith 2008-12-29 05:25:11 UTC
mingw32 does not support weak definitions, only "weak externals"   As documented
in ld.info:

_weak externals_
     The Windows object format, PE, specifies a form of weak symbols
     called weak externals.  When a weak symbol is linked and the
     symbol is not defined, the weak symbol becomes an alias for some
     other symbol.  There are three variants of weak externals:
        * Definition is searched for in objects and libraries,
          historically called lazy externals.

        * Definition is searched for only in other objects, not in
          libraries.  This form is not presently implemented.

        * No search; the symbol is an alias.  This form is not presently
          implemented.
     As a GNU extension, weak symbols that do not specify an alternate
     symbol are supported.  If the symbol is undefined when linking,
     the symbol uses a default value.
Comment 2 tcl_de 2008-12-29 09:17:49 UTC
(In reply to comment #1)
>      As a GNU extension, weak symbols that do not specify an alternate
>      symbol are supported.  If the symbol is undefined when linking,
>      the symbol uses a default value.

Well, doesn't that paragraph tell that me that as a GNU extension weak symbols
are supported?
Shouldn't those two files just compile cleanly on mingw32 then as they do on
linux because "as a GNU extension weak symbols are supported"?
Comment 3 tcl_de 2009-03-18 14:57:32 UTC
@Dave Korn: I added you as a CC because I saw that thread on the mailinglist
where you say that you want to make weak symbols work on cygwin with binutils.
The same I write about mingw32 here is true for cygwin 1.7 (binutils
2.18.50.20080625), too. The weak.o generated by binutils is identical on mingw32
and cygwin.

In the meantime I found out why it couldn't work: (I suppose)
I switched to
>GNU assembler (GNU Binutils) 2.19.1
>Copyright 2007 Free Software Foundation, Inc.
>This program is free software; you may redistribute it under the terms of
>the GNU General Public License version 3 or later.
>This program has absolutely no warranty.
>This assembler was configured for a target of `mingw32'.
and it produces exactly the same output as version 2.19.

But gas does not correctly set the field Characteristics the auxiliary record
(format 3 for weak externals) of the weak external automatically generated for
the weak symbol.
GNU as sets it to IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY but it should actually be
set to IMAGE_WEAK_EXTERN_SEARCH_ALIAS.

The reason I think it's like that is because I tried to link the weak.o produced
by gas to main.obj produced by visual c++ with ms link and the output is:
>Microsoft (R) Incremental Linker Version 9.00.21022.08
>Copyright (C) Microsoft Corporation.  All rights reserved.
>
>main.obj : error LNK2019: unresolved external symbol _function referenced in
function _main
>weak.o : error LNK2001: unresolved external symbol _function
>main.exe : fatal error LNK1120: 1 unresolved externals

If I change the field Characteristics to IMAGE_WEAK_EXTERN_SEARCH_ALIAS
link will output 
>Microsoft (R) Incremental Linker Version 9.00.21022.08
>Copyright (C) Microsoft Corporation.  All rights reserved.
and main.exe will output
>Hello from the weak function

and when i even link another file strong.o produced by compiling strong.c with gcc
===== strong. c=======================
#include <stdio.h>

void function()
{
    printf("Hello from the strong function\n");
}
===============================================
to weak.o and main.obj with link, main.exe will output:
>Hello from the strong function

Note that changing Characteristics to IMAGE_WEAK_EXTERN_SEARCH_LIBRARY will also
lead to the same errors as IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY and link outputs
are the same.
So please modify gas to use IMAGE_WEAK_EXTERN_SEARCH_ALIAS for the field
Characteristics at least for weak externals that are automatically generated as
GNU extension for weak symbols.

Anyways I can't link any of the three versions of weak.o with a main.obj using
GNU ld (called from gcc) because it will always output:
>Warning: .drectve `/DEFAULTLIB:"LIBCMT" /DEFAULTLIB:"OLDNAMES" ' unrecognized
>main.obj:(.text+0x4): undefined reference to `function'
>collect2: ld returned 1 exit status
Comment 4 tcl_de 2009-03-18 15:00:53 UTC
Created attachment 3829 [details]
This is the original weak.o generated by gas

This is the original weak.o generated by gas
Comment 5 tcl_de 2009-03-18 15:02:07 UTC
Created attachment 3830 [details]
This is the modified weak.o (with IMAGE_WEAK_EXTERN_SEARCH_ALIAS)
Comment 6 Dave Korn 2009-03-19 02:14:00 UTC
  Hi tcl_de, thanks for Cc'ing me into this bug report.

(In reply to comment #2)
> (In reply to comment #1)
> >      As a GNU extension, weak symbols that do not specify an alternate
> >      symbol are supported.  If the symbol is undefined when linking,
> >      the symbol uses a default value.
> 
> Well, doesn't that paragraph tell that me that as a GNU extension weak symbols
> are supported?
> Shouldn't those two files just compile cleanly on mingw32 then as they do on
> linux because "as a GNU extension weak symbols are supported"?

  You have misread the paragraph.  As a gnu extension, "weak symbols that do not
specify an alternate symbol" are supported.

  On PE targets, binutils supports weak externals, a limited form of weak symbol
that acts as an alias for a default value.  As a GNU extension (above what MSVC
toolchain) supports, you may define these symbols *without* defining the default
symbol that they act as an alias for. 

  Normally (MSVC toolchain) you must supply a default definition along with
every weak symbol, in the same .o file.  Refer to this final line of the second
paragraph of section 5.5.3 (Auxiliary Format 3: Weak externals) of the PE-COFF
spec v8:

  "  The external symbol, sym2, must always be linked; typically, it is defined
in the module that contains the weak reference to sym1.  "

  IIUC the GNU extension is to allow sym2 to optionally be an undefined external
symbol, rather than defined in the module.

  The weak support in binutils is currently limited, as it was only developed
enough to provide interoperability with the MSVC toolchain, which uses these
"weak externals" to resolve class destructors.  There are moves underfoot to
extend the implementation to fully (or at least more fully) support ELF weak
symbols, but that will take a little time.

  In the matter of this current bug, I found a post from Danny which summarizes
the situation:
  http://sourceware.org/ml/binutils/2007-06/msg00227.html

> > Does the pe-i386 object format support weak symbol definitions?
> No.
> > Does the pe-i386 object format support weak symbol references?
> PE-COFF spec supports "weak externs".

and in particular he says:

> weak aliases also seem to work (with GNU ld) even though the
> IMAGE_WEAK_EXTERN_SEARCH_ALIAS characteristic is not set.
>
> I imagine the  MS linker would have trouble with GNU weak aliases
> without the flag.

  It seems the GNU linker does too.  I think that your test case ought to be
possible to make work using the existing support, though, and we should consider
whether setting the characteristic field isn't the right thing to do.

Comment 7 tcl_de 2009-03-21 09:39:38 UTC
Dave, you should probably have a look at
http://sourceware.org/bugzilla/show_bug.cgi?id=2729.
In that bug, you can see how the interix people dealt with the problem... (they
did use IMAGE_WEAK_EXTERN_SEARCH_ALIAS).

The way I understand what the GNU extension really is, is that gas automatically
renames the original function to .weak.##nameoffunction##. and creates a weak
extern ##nameoffunction## refering to .weak.##nameoffunction## which makes
##nameoffunction## a normal pecoff weak external

The requirement that sym2 is always linked is met in my testcase because the
weak extern/symbol definition is in the same object file as sym2. (otherwise
link.exe would probably not link my object files...)

So as far as I can understand that problem all of this should theoretically also
work in gnu as and ld. 
Comment 8 Martin Whitaker 2011-10-22 20:06:24 UTC
I've recently encountered this issue. Was any further progress made on determining if a fix was possible?
Comment 9 Jackie Rosen 2014-02-16 18:23:51 UTC Comment hidden (spam)