Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 10 Nov 2012 00:25:32 +0100
From:      Dimitry Andric <dim@FreeBSD.org>
To:        Steve Kargl <sgk@troutmask.apl.washington.edu>
Cc:        freebsd-current@freebsd.org
Subject:   Re: clang and static linking?
Message-ID:  <509D90EC.5040302@FreeBSD.org>
In-Reply-To: <509D5BC3.9020704@FreeBSD.org>
References:  <20121108231349.GA79485@troutmask.apl.washington.edu> <509D4548.7030806@FreeBSD.org> <20121109182810.GA61338@troutmask.apl.washington.edu> <509D5BC3.9020704@FreeBSD.org>

next in thread | previous in thread | raw e-mail | index | archive | help
On 2012-11-09 20:38, Dimitry Andric wrote:
> On 2012-11-09 19:28, Steve Kargl wrote:
...
>> I'll see what I can do. sasmp is a fairly large OpenMPI program.
>
> Sorry, never mind that.  I found a simple testcase:
>
> #include <math.h>
>
> int main(int argc, char *argv[])
> {
> 	return isnan((double)argc) + isnan((float)argc);
> }
>
> Building with -lm -static will trigger the link error.  I'm
> investigating where the problem is.

I think I have an idea now what causes this.  When you compile the above
program with gcc, it emits a call to __isnanf(), but uses its builtin
for isnan().  When you statically link it using -lm, the linker finds
__isnanf() in libm.a's s_isnan.o member.  It ignores libc.a's isnan.o
member, because it does not need any additional symbols from it.

In contrast, clang emits calls to both isnan() and __isnanf(), as the
former is not a clang builtin.  When you statically link with -lm, the
linker first finds __isnanf() in libm.a's s_isnan.o member, just like
before.  Then, it finds isnan(), as a weak reference, in libc.a's
isnan.o member, so it wants to load that too.  This causes a conflict,
because __isnanf() is defined both in libm.a's s_isnan.o member, and in
libc.a's isna.o member.

Note that you will see the same link error, if you use gcc -fno-builtin
to compile the above program, and for the same reason: the copies of
__isnanf() in libm.a and libc.a conflict.

There seem to be two ways out of this conundrum: the easier one is to
make clang also use a builtin for isnan(), for example by modifying the
isnan() macro in math.h, letting it invoke __builtin_isnan() instead.
However, this just papers over the issue.

The more difficult way out is to not define any duplicate functions in
libc.a and libm.a.  For the shared libraries, this should not be a
problem, since the dynamic linker will figure out which of the two
copies will get precedence.  The functions must stay available for
backwards compatibility reasons anyway.

For static libraries, this compatibility seems to be unnecessary, as
they will only be used to link new programs.  Therefore, it would
probably be best to remove the whole isnan.o member from libc.a, and
move all the isnan functions to libm.a instead.

Currently, isnan() is commented out in lib/msun/src/s_isnan.c, maybe we
can enable it whenever PIC is not defined?  Then we could simply skip
building lib/libc/gen/isnan.c for libc.a.

Anther possible solution is to split off isnanf() and __isnanf() to
separate files, then build s_isnanf.o for libm.a, but skip building
isnanf.o for libc.a.  This might be a little cleaner.



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?509D90EC.5040302>