Bug 18859

Summary: Gold linker does not fully respect -no-as-needed
Product: binutils Reporter: Evgeniy Stepanov <eugeni.stepanov>
Component: goldAssignee: Cary Coutant <ccoutant>
Status: RESOLVED FIXED    
Severity: normal CC: ian
Priority: P2    
Version: 2.26   
Target Milestone: ---   
Host: Target:
Build: Last reconfirmed:

Description Evgeniy Stepanov 2015-08-20 20:53:31 UTC
Gold and ld behave differently when a shared library is first mentioned when -as-needed is in effect, and then again after -no-as-needed. Ld generates a DT_NEEDED entry for such library, and gold does not.

$ cat 1.c
int main() { return 0; }

# BFD linker
$ g++ 1.c -Wl,-as-needed -lutil -Wl,-no-as-needed -lutil -fuse-ld=bfd && readelf -d a.out  | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libutil.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

# Gold linker
$ g++ 1.c -Wl,-as-needed -lutil -Wl,-no-as-needed -lutil -fuse-ld=gold && readelf -d a.out  | grep NEEDED
 0x0000000000000001 (NEEDED)             Shared library: [libstdc++.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libm.so.6]
 0x0000000000000001 (NEEDED)             Shared library: [libgcc_s.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]
Comment 1 Cary Coutant 2015-08-20 22:26:01 UTC
> Gold and ld behave differently when a shared library is first mentioned when
> -as-needed is in effect, and then again after -no-as-needed. Ld generates a
> DT_NEEDED entry for such library, and gold does not.

Why are you expecting a NEEDED entry for libutil? There's nothing in your main program that depends on anything in that library, so by the definition of the --as-needed option, gold is doing exactly what I would expect.

Your command line lists "-lutil" twice, once between the as-needed options, and once after. Gold ignores any shared library listed on the command line that it has already processed.

If you want the library in your DT_NEEDED list, remove the first copy from your command line (the one between --as-needed and --no-as-needed).
Comment 2 Evgeniy Stepanov 2015-08-20 22:54:39 UTC
There is some context here:
https://llvm.org/bugs/show_bug.cgi?id=15823

In the clang driver, we add a static library that implements wrappers for libutil functions, i.e. it exports functions with the same names and calls the real libutil functions with dlsym(RTLD_NEXT). To ensure that the executable still depends on libutil, we add -no-as-needed -lutil to the end of the link line - otherwise the linker thinks that all libutil dependencies are already satisfied by the wrapper library.

The first "-as-needed -lutil" comes from the clang command line.
Comment 3 Cary Coutant 2015-08-22 00:46:46 UTC
OK, I have a patch in the works to have gold mark the shared object as --no-as-needed if it appears anywhere on the command line when --no-as-needed is in effect.

As an aside, though, have you considered using --wrap for your wrapper functions? Your use case is exactly what that option was designed for.
Comment 4 Evgeniy Stepanov 2015-08-24 16:14:56 UTC
Thank you!

--wrap does not work for prebuilt shared libraries, and we need to intercept at least some functions in those, too (ex. malloc).
Comment 5 Sourceware Commits 2015-08-26 01:40:07 UTC
The master branch has been updated by Cary Coutant <ccoutant@sourceware.org>:

https://sourceware.org/git/gitweb.cgi?p=binutils-gdb.git;h=4bfacfd359a1f8d026d1a350f56f2f5d70b6cb65

commit 4bfacfd359a1f8d026d1a350f56f2f5d70b6cb65
Author: Cary Coutant <ccoutant@gmail.com>
Date:   Fri Aug 21 12:32:33 2015 -0700

    Fix --no-as-needed when shared library is listed twice on the command line.
    
    When a shared library is listed twice on the command line, the linker
    ignores the second mention. If the first mention is in the scope of
    an --as-needed option, and the second one is under the scope of a
    --no-as-needed option, the --no-as-needed should take effect, but
    doesn't.  This patch keeps track of the objects we've already seen,
    and updates the --as-needed flag so that if a shared object is ever
    seen with --no-as-needed, it will be marked as such.
    
    gold/
    	PR gold/18859
    	* object.cc (Input_objects::add_object): Store objects in a map,
    	indexed by soname; update as-needed flag when necessary.
    	* object.h (Object::clear_as_needed): New method.
    	(Input_objects::so_names_): Change from set to map.
Comment 6 Cary Coutant 2015-08-26 01:49:24 UTC
Fixed on master.