svn commit: r270803 - head/libexec/rtld-elf

Konstantin Belousov kostikbel at gmail.com
Sat Aug 30 19:37:05 UTC 2014


On Fri, Aug 29, 2014 at 02:45:55PM -0500, Bryan Drewery wrote:
> My only uses so far have been observing which file is loaded for a
> library with dlopen(3) and where symbols are resolved from. Seeing where
> symbols are resolved from is useful for both dlopen(3)/dlsym(3) usage
> and LD_PRELOAD.
Ok.

Note that there are no traces of why the symbols where resolved from
the specified object, and, why that symbol was selected (one object
may contain several symbols with the same name, for several reasons).

> 
> I've written an application that "optionally" allows using some
> libraries such as libtcl to be used without requiring the library at
> build time or startup. At build time the library's headers are used to
> generate wrapper functions for every symbol needed. The library is not
> linked in. When the binary is ran it starts up fine if libtcl is
> missing. At runtime if TCL is enabled then it will attempt to
> dlopen(libtcl.so.VER) using the VER its symbols was compiled against. If
> it cannot find it then the feature is disabled. It uses dlsym(3) to load
> all symbols into a table and the wrapper functions use that table via
> hash table lookups.
Note that ELF PLT symbols (i.e. function call sites) resolution is lazy
by default, i.e. the only tricky part to do for this with the standard
tools is to avoid writing the DT_NEEDED tag into the binary you construct.

Newer GNU ld has interesting options like --unresolved-symbols=ignore-all,
or --warn-unresolved-symbols, which seemingly allow to link the binary
even with unresolved symbols.

If you use then dlopen(libname, RTLD_LAZY | RTLD_GLOBAL) before calling
the functions from the library, you should get what you want without
needing to laborously provide stubs and use dlsym().

And, this cannot work for non-PLT relocations, e.g. references to global
variables.

> 
> This all pretty convoluted and only done to avoid requiring a library at
> startup. The application is distributed pre-compiled for specific OS
> releases and not intended to be compiled manually.
> 
> Anyway some examples from GNU's rtld:
> 
> > # env LD_DEBUG=help ./app
> > Valid options for the LD_DEBUG environment variable are:
> > 
> >   libs        display library search paths
> >   reloc       display relocation processing
> >   files       display progress for input file
> >   symbols     display symbol table processing
> >   bindings    display information about symbol binding
> >   versions    display version dependencies
> >   all         all previous options combined
> >   statistics  display relocation statistics
> >   unused      determined unused DSOs
> >   help        display this help message and exit
> > 
> > To direct the debugging output into a file instead of standard output
> > a filename can be specified using the LD_DEBUG_OUTPUT environment variable.
> 
> With libs:
> 
> > # env LD_DEBUG=libs ./app
> > ...
> >       9328:     find library=libtcl.so [0]; searching
> >       9328:      search cache=/etc/ld.so.cache
> >       9328:      search path=/lib64/tls/x86_64:/lib64/tls:/lib64/x86_64:/lib64:/usr/lib64/tls/x86_64:/usr/lib64/tls:/usr/lib64/x86_64:/usr/lib64                (system search path)
> >       9328:       trying file=/lib64/tls/x86_64/libtcl.so
> >       9328:       trying file=/lib64/tls/libtcl.so
> >       9328:       trying file=/lib64/x86_64/libtcl.so
> >       9328:       trying file=/lib64/libtcl.so
> >       9328:       trying file=/usr/lib64/tls/x86_64/libtcl.so
> >       9328:       trying file=/usr/lib64/tls/libtcl.so
> >       9328:       trying file=/usr/lib64/x86_64/libtcl.so
> >       9328:       trying file=/usr/lib64/libtcl.so
> >       9328:
> >       9328:     find library=libpthread.so.0 [0]; searching
> >       9328:      search path=/usr/lib64         (system search path)
> >       9328:       trying file=/usr/lib64/libpthread.so.0
> >       9328:      search cache=/etc/ld.so.cache
> >       9328:       trying file=/lib64/libpthread.so.0
> >       9328:
> >       9328:
> >       9328:     calling init: /lib64/libpthread.so.0
> >       9328:
> >       9328:
> >       9328:     calling init: /usr/lib64/libtcl.so
> >       9328:
> >       9328:     find library=libnss_compat.so.2 [0]; searching
> >       9328:      search cache=/etc/ld.so.cache
> >       9328:       trying file=/lib64/libnss_compat.so.2
> >       9328:
> >       9328:     find library=libnsl.so.1 [0]; searching
> >       9328:      search cache=/etc/ld.so.cache
> >       9328:       trying file=/lib64/libnsl.so.1
> >       9328:
> >       9328:
> >       9328:     calling init: /lib64/libnsl.so.1
> >       9328:
> >       9328:
> >       9328:     calling init: /lib64/libnss_compat.so.2
> >       9328:
> >       9328:     find library=libnss_nis.so.2 [0]; searching
> >       9328:      search cache=/etc/ld.so.cache
> >       9328:       trying file=/lib64/libnss_nis.so.2
> >       9328:
> >       9328:     find library=libnss_files.so.2 [0]; searching
> >       9328:      search cache=/etc/ld.so.cache
> >       9328:       trying file=/lib64/libnss_files.so.2
> >       9328:
> >       9328:
> >       9328:     calling init: /lib64/libnss_files.so.2
> >       9328:
> >       9328:
> >       9328:     calling init: /lib64/libnss_nis.so.2
> > ^C
> >       9328:     calling fini: /usr/lib64/libtcl.so [0]
> >       9328:
> >       9328:
> >       9328:     calling fini: /lib64/libm.so.6 [0]
> >       9328:
> >       9328:
> >       9328:     calling fini: /lib64/libdl.so.2 [0]
> >       9328:
> >       9328:
> >       9328:     calling fini: /lib64/libpthread.so.0 [0]
> >       9328:
> >       9328:
> >       9328:     calling fini: /lib64/libnss_compat.so.2 [0]
> >       9328:
> >       9328:
> >       9328:     calling fini: /lib64/libnss_nis.so.2 [0]
> >       9328:
> >       9328:
> >       9328:     calling fini: /lib64/libnsl.so.1 [0]
> >       9328:
> >       9328:
> >       9328:     calling fini: /lib64/libnss_files.so.2 [0]
> >       9328:
> >       9328:
> >       9328:     calling fini: /lib64/libc.so.6 [0]
> 
> With symbols:
> 
> > # LD_DEBUG=symbols ./app
> > ...
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/lib64/libdl.so.2 [0]
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/libstdc++.so.6 [0]
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/lib64/libm.so.6 [0]
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/libgcc_s.so.1 [0]
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/lib64/libc.so.6 [0]
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/usr/lib64/libcrypto.so.1.0.0 [0]
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/lib64/libz.so.1 [0]
> >       9355:     symbol=Tcl_SetObjResult;  lookup in file=/usr/lib64/libtcl.so [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=./netplay [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/lib64/libdl.so.2 [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/libstdc++.so.6 [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/lib64/libm.so.6 [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/usr/lib/gcc/x86_64-pc-linux-gnu/4.8.2/libgcc_s.so.1 [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/lib64/libc.so.6 [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/lib64/ld-linux-x86-64.so.2 [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/usr/lib64/libcrypto.so.1.0.0 [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/lib64/libz.so.1 [0]
> >       9355:     symbol=Tcl_GetObjResult;  lookup in file=/usr/lib64/libtcl.so [0]
> 
> 
> I would love to work on adding such a feature to ours, especially if it
> can assist with debugging rtld itself. I would think with some
> predict_false() checks we could avoid much of the performance penalties.
As I said, for debugging rtld, currently existing or, probably, any
predefined set of debugging statements is mostly useless.  A startup
problems usually results in coredumps, which is compfortably debugged
by loading core with debugging symbols (-g) in gdb.

If you can determine useful set of the debugging output for application
programmers to introspect the rtld activity, I am all for adding it
and enabling LD_DEBUG unconditionally.

> 
> As a side note I think I may have found an rtld issue (on 8.4) with -32
> handling. Being a production machine I don't want to attempt installing
> a DEBUG rtld to figure out the problem. Having LD_DEBUG would have been
> useful on this as well.
> 
> The issue I ran into with -32 was from converting a i386 system to
> amd64. I have hundreds of out-of-ports binaries that need to be manually
> recompiled. To allow delaying this task for a bit I copied all of the
> libraries from /usr/local/lib from the old i386 system to
> /usr/local/lib32/compat/system and added all of the paths in there to
> ldconfig:
> 
> > [~] # ldconfig -32 -r|head -n3
> > /var/run/ld-elf32.so.hints:
> >         search directories: /usr/lib32:/usr/local/lib32/compat/system:/usr/local/lib32/compat/system/mysql:/usr/local/lib32/compat/system/gnutls3:/usr/local/lib32/compat/system/pth:/usr/local/lib32/compat/system/qt4:/usr/local/lib32/compat/system/tdom0.8.3:/usr/local/lib32/compat/system/gcc46:/usr/local/lib32/compat/system/gcc47:/usr/local/lib32/compat/system/gcc48:/usr/local/lib32/compat/system/gcc49:/usr/local/lib32/compat/system/event2:/usr/local/lib32/compat/pkg:/usr/local/lib32/compat
> 
> It worked for 90% of the system but then I ran into some libraries that
> refused to find their own dependencies. The issue seemingly is that
> dependencies for libraries that are also in the -32 path are not looked up.
> 
> For example:
> 
> > [~] # ldd -a /usr/local/lib32/compat/system/libssl.so
> > /usr/local/lib32/compat/system/libssl.so:
> >         libcrypto.so.8 => not found (0x0)
> >         libthr.so.3 => /usr/lib32/libthr.so.3 (0x310fb000)
> >         libc.so.7 => /usr/lib32/libc.so.7 (0x29165000)
> > /usr/lib32/libthr.so.3:
> >         libc.so.7 => /usr/lib32/libc.so.7 (0x29165000)
> > [~] # ldconfig -32 -r|grep libcrypto.so.8
> >         105:-lcrypto.8 => /usr/local/lib32/compat/system/libcrypto.so.8
> > [~] # readelf -a /usr/local/lib32/compat/system/libssl.so|egrep "(path|NEEDED)"
> >  0x00000001 (NEEDED)                     Shared library: [libcrypto.so.8]
> >  0x00000001 (NEEDED)                     Shared library: [libthr.so.3]
> >  0x00000001 (NEEDED)                     Shared library: [libc.so.7]
> >  0x0000000f (RPATH)                      Library rpath: [/usr/local/lib]
> 
> My guess is it is the RPATH. I am not sure without a simple debug ability.
> 
> -- 
> Regards,
> Bryan Drewery
> 


-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.freebsd.org/pipermail/svn-src-head/attachments/20140830/42b7a25a/attachment.sig>


More information about the svn-src-head mailing list