From owner-freebsd-current@FreeBSD.ORG Fri Nov 9 23:25:30 2012 Return-Path: Delivered-To: freebsd-current@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52]) by hub.freebsd.org (Postfix) with ESMTP id 74E8BC2B for ; Fri, 9 Nov 2012 23:25:30 +0000 (UTC) (envelope-from dim@FreeBSD.org) Received: from tensor.andric.com (cl-327.ede-01.nl.sixxs.net [IPv6:2001:7b8:2ff:146::2]) by mx1.freebsd.org (Postfix) with ESMTP id 2B58B8FC08 for ; Fri, 9 Nov 2012 23:25:30 +0000 (UTC) Received: from [192.168.0.6] (spaceball.home.andric.com [192.168.0.6]) (using TLSv1 with cipher DHE-RSA-CAMELLIA256-SHA (256/256 bits)) (No client certificate requested) by tensor.andric.com (Postfix) with ESMTPSA id 75D1F5C59; Sat, 10 Nov 2012 00:25:29 +0100 (CET) Message-ID: <509D90EC.5040302@FreeBSD.org> Date: Sat, 10 Nov 2012 00:25:32 +0100 From: Dimitry Andric Organization: The FreeBSD Project User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:17.0) Gecko/17.0 Thunderbird/17.0 MIME-Version: 1.0 To: Steve Kargl Subject: Re: clang and static linking? References: <20121108231349.GA79485@troutmask.apl.washington.edu> <509D4548.7030806@FreeBSD.org> <20121109182810.GA61338@troutmask.apl.washington.edu> <509D5BC3.9020704@FreeBSD.org> In-Reply-To: <509D5BC3.9020704@FreeBSD.org> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Cc: freebsd-current@freebsd.org X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 09 Nov 2012 23:25:30 -0000 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 > > 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.