How do I diagnose why a shared library is not found? - linux

I am trying to run an app which is linked against libboost_system.so
$ ./app
app: error while loading shared libraries: libboost_system.so.1.63.0: cannot open shared object file: \
No such file or directory
If I run ldd on the app, it shows it can't find the library:
$ ldd ./app
linux-vdso.so.1 (0x00007ffdedb94000)
libboost_system.so.1.63.0 => not found
libpcap.so.1 => /lib64/libpcap.so.1 (0x00007f19a1a7b000)
librt.so.1 => /lib64/librt.so.1 (0x00007f19a1a70000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f19a1a69000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f19a1879000)
libm.so.6 => /lib64/libm.so.6 (0x00007f19a1733000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f19a1716000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f19a16f4000)
libc.so.6 => /lib64/libc.so.6 (0x00007f19a152a000)
/lib64/ld-linux-x86-64.so.2 (0x00007f19a1ae5000)
The library is present on my system:
$ locate libboost_system.so.1.63.0
/usr/local/lib/libboost_system.so.1.63.0
$ ls -la /usr/local/lib/libboost_system*
-rw-r--r--. 1 root root 47014 Jul 2 16:57 /usr/local/lib/libboost_system.a
lrwxrwxrwx. 1 root root 25 Jul 2 16:57 /usr/local/lib/libboost_system.so -> libboost_system.so.1.63.0
-rwxr-xr-x. 1 root root 19816 Jul 2 16:57 /usr/local/lib/libboost_system.so.1.63.0
ld is configured with /usr/local/lib:
$ ld --verbose | grep SEARCH_DIR | sed 's/; /\n/g'
SEARCH_DIR("=/usr/x86_64-redhat-linux/lib64")
SEARCH_DIR("=/usr/lib64")
SEARCH_DIR("=/usr/local/lib64")
SEARCH_DIR("=/lib64")
SEARCH_DIR("=/usr/x86_64-redhat-linux/lib")
SEARCH_DIR("=/usr/local/lib") <----- here
SEARCH_DIR("=/lib")
SEARCH_DIR("=/usr/lib")
I've also run ldconfig to refresh the cache, but that doesn't help.
I tried searching for RPATH or RUNPATH with readelf, neither are specified:
$ readelf -d ./app | grep -i path
< no results >
If I explicitly set LD_LIBARY_PATH then the library is found:
$ LD_LIBRARY_PATH=/usr/local/lib ldd ./app
linux-vdso.so.1 (0x00007fffa9a5d000)
libboost_system.so.1.63.0 => /usr/local/lib/libboost_system.so.1.63.0 (0x00007f5fff664000)
libpcap.so.1 => /lib64/libpcap.so.1 (0x00007f5fff5fc000)
librt.so.1 => /lib64/librt.so.1 (0x00007f5fff5f1000)
libdl.so.2 => /lib64/libdl.so.2 (0x00007f5fff5ea000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f5fff3fa000)
libm.so.6 => /lib64/libm.so.6 (0x00007f5fff2b4000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f5fff297000)
libpthread.so.0 => /lib64/libpthread.so.0 (0x00007f5fff275000)
libc.so.6 => /lib64/libc.so.6 (0x00007f5fff0ab000)
/lib64/ld-linux-x86-64.so.2 (0x00007f5fff66b000)
Why can't ld find libboost_system.so.1.63.0 without specifying LD_LIBRARY_PATH?

You are looking at the "wrong" linker. ld is the static linker and isn't what's used by at runtime to locate the shared libraries.
The dynamic linker, ld.so, is what locates shared libraries.
The dynamic linker does look at the LD_LIBRARY_PATH and that's why it works if you set it.
If you want to update the search locations for dynamic linker (and not want to set LD_LIBRARY_PATH), you can create a file in /etc/ld.so.conf.d/ and update /etc/ld.so.cache with ldconfig.

The diagnostic is activated by LD_DEBUG (cf. man ld.so):
LD_DEBUG=libs ./a.out
It shows the search paths that the loader tried: ($LD_LIBRARY_PATH, R[UN]PATH from the app or library's ELF, ld.so.cache).
Its output is a little long to copy here, but would look like this:
265: find library=libboost_system.so.1.63.0 [0]; searching
265: search path= [...] (LD_LIBRARY_PATH)
[trying many files...]
265: search path= [...] (RUNPATH from file ./app)
[still trying many files...]
265: search cache=/etc/ld.so.cache
[still trying many files...]
In your case, you'd probably have seen that /usr/local/lib was not in the cache. Depending on the distribution, it may look by default in /usr/local/lib/x86_64-linux-gnu or /usr/local/lib64 or none at all.

Related

Circular reference between libc.so.6 and liblsp.so?

▶ldd /lib/x86_64-linux-gnu/libc.so.6
linux-vdso.so.1 (0x00007fff2b856000)
/lib/$LIB/liblsp.so => /lib/lib/x86_64-linux-gnu/liblsp.so (0x00007f472effc000)
/lib64/ld-linux-x86-64.so.2 (0x00007f472f3f5000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f472efd5000)
▶ldd /lib/lib/x86_64-linux-gnu/liblsp.so
linux-vdso.so.1 (0x00007ffe305ee000)
/lib/$LIB/liblsp.so => /lib/lib/x86_64-linux-gnu/liblsp.so (0x00007f28eea81000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f28eea5a000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f28ee868000)
/lib64/ld-linux-x86-64.so.2 (0x00007f28eee8d000)
We can find a circular reference between libc.so.6 and liblsp.so. How does it works?
How does it works?
libc.so.6 doesn't really depend on liblsp.so. You can verify this with readelf -d /lib/x86_64-linux-gnu/libc.so.6 | grep NEEDED.
The reason ldd shows it is that it's listed in your /etc/ld.so.preload.
As Nate Eldredge commented, this "cycle" doesn't matter -- the loader needs to load dependent libraries which aren't already loaded. If a library is already loaded, the loader simply increments its reference count.

Newly built gcc not being used even after setting $PATH

My server has GCC4 and I need newer version, so I built GCC7.3.0 and added the path to the $PATH variable. After this, gcc -v and g++ -v points to the correct version:
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=/users/home/m/GCC-7.3.0/bin/../libexec/gcc/x86_64-pc-linux-gnu/7.3.0/lto-wrapper
Target: x86_64-pc-linux-gnu
Configured with: /home/m/gccbuild/../srcdir/configure --prefix=/home/m/GCC-7.3.0 --enable-languages=c,c++,fortran,go --disable-multilib
Thread model: posix
gcc version 7.3.0 (GCC)
However, I tried compiling a simple hello.cc program and ldd a.out gives:
linux-vdso.so.1 => (0x00007ffe609bb000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fa0bff67000)
libm.so.6 => /lib64/libm.so.6 (0x00007fa0bfc65000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fa0bfa4f000)
libc.so.6 => /lib64/libc.so.6 (0x00007fa0bf681000)
/lib64/ld-linux-x86-64.so.2 (0x00007fa0c026e000)
From here, was expecting something like:
libstdc++.so.6 => /users/home/m/GCC-7.3.0/lib64/libstdc++.so.6 (0x0000123456789000)
libgcc_s.so.1 => /users/home/m/GCC-7.3.0/lib64/libgcc_s.so.1 (0x0000123456ABC000)
Also, cat /proc/version gives:
Linux version 3.10.0-1127.el7.x86_64 (mockbuild#kbuilder.bsys.centos.org) (gcc version 4.8.5 20150623 (Red Hat 4.8.5-39) (GCC) ) #1 SMP Tue Mar 31 23:36:51 UTC 2020
EDIT:
Output to grep configure config.status within gcc build directory:
# Generated by configure.
# Compiler output produced by configure, useful for debugging
# configure, is in config.log if it exists.
configured by /home/s18002/gccbuild/../srcdir/configure, generated by GNU Autoconf 2.64,
ac_configure_extra_args=
ac_configure_extra_args="$ac_configure_extra_args --silent"
set X '/bin/sh' '/home/s18002/gccbuild/../srcdir/configure' '--prefix=/home/m/GCC-7.3.0' '--disable-multilib' '--enable-languages=c,c++,fortran,go,lto' $ac_configure_extra_args --no-create --no-recursion
"L) $$r/$(TARGET_SUBDIR)/libstdc++-v3/scripts/testsuite_flags --build-includes; else echo -funconfigured-libstdc++-v3 ; fi` -L$$r/$(TARGET_SUBDIR)/li"\
S["extra_host_zlib_configure_flags"]=""
S["extra_host_libiberty_configure_flags"]="--enable-shared"
S["extra_linker_plugin_configure_flags"]=""
S["extra_isl_gmp_configure_flags"]="--with-gmp- builddir=$$r/$(HOST_SUBDIR)/gmp"
S["extra_mpc_mpfr_configure_flags"]="--with-mpfr-include=$$s/mpfr/src --with-mpfr-lib=$$r/$(HOST_SUBDIR)/mpfr/src/.libs"
S["extra_mpc_gmp_configure_flags"]="--with-gmp-include=$$r/$(HOST_SUBDIR)/gmp --with-gmp-lib=$$r/$(HOST_SUBDIR)/gmp/.libs"
S["extra_mpfr_configure_flags"]="--with-gmp-include=$$r/$(HOST_SUBDIR)/gmp --with-gmp-lib=$$r/$(HOST_SUBDIR)/gmp/.libs"
S["extra_liboffloadmic_configure_flags"]=""
S["TOPLEVEL_CONFIGURE_ARGUMENTS"]="/home/s18002/gccbuild/../srcdir/configure --prefix=/home/s18002/GCC-7.3.0 --enable-languages=c,c++,fortran,go --disable-multilib"
# Let's still pretend it is `configure' which instantiates (i.e., don't
configure_input='Generated from '`
`' by configure.'
configure_input="$ac_file. $configure_input"
case $configure_input in #(
ac_sed_conf_input=`$as_echo "$configure_input" |
*) ac_sed_conf_input=$configure_input;;
s|#configure_input#|$ac_sed_conf_input|;t t
The package I was trying to install got installed, which means it is using gcc7. How can I make sure GCC7 is used locally for all my purposes?
Make sure you are compiling with g++ and not gcc:
$ gcc test.c
$ ldd a.out
linux-vdso.so.1 => (0x00007ffcbdd71000)
libc.so.6 => /lib64/libc.so.6 (0x00007f3b23c32000)
/lib64/ld-linux-x86-64.so.2 (0x00007f3b24000000)
$ g++ test.c
$ ldd a.out
linux-vdso.so.1 => (0x00007ffedc577000)
libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007f745ed73000)
libm.so.6 => /lib64/libm.so.6 (0x00007f745ea71000)
libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007f745e85b000)
libc.so.6 => /lib64/libc.so.6 (0x00007f745e48d000)
/lib64/ld-linux-x86-64.so.2 (0x00007f745f07a000)

Linking: Why does linker not honour symlink to library?

I have the following C program:
#include <stdio.h>
#include <zlib.h>
int main()
{
z_stream strm;
int integer = 0;
scanf("heloworld %d", &integer);
printf("ok\n");
if (integer == 10)
{
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
deflateInit(&strm, 0);
}
return 0;
}
This is a basic helloworld program which uses zlib.
If I search for the libz library, I can find it under /usr/lib/x86_64-linux-gnu/libz.so:
$ ls -lah libz.so
lrwxrwxrwx 1 root root 40 May 20 14:55 libz.so -> /usr/lib/x86_64-linux-gnu/libz.so.1.2.11
and it is pointing to the real version of libz rather than the soname.
I compile it with the following command and check the dependencies:
$ gcc a.c -lz
$ ldd a.out
linux-vdso.so.1 (0x00007ffec44b6000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f6674055000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f6673e63000)
/lib64/ld-linux-x86-64.so.2 (0x00007f667408c000)
How is it pointing to libz.so.1 instead of libz.so.1.2.11 (realname) since the symlink of libz.so.1 is pointing there? I am assuming that the linker is using the symlink however this is not the case.
Further to this, if I perform the following command:
$ objdump -p libz.so.1.2.11 | grep SONAME
SONAME libz.so.1
My question is, is it using the symlink name or the SONAME from the file the symlink provides?
If the linker put libz.so.1.2.11 in your executable, then it would break when you updated the library. Instead it puts the major version known to ldconfig in the executable, which is in turn a link to the current installed version.
See ldconfig http://man7.org/linux/man-pages/man8/ldconfig.8.html
I have discovered that under /lib/x86_64-linux-gnu there are two symlinks for libz.so which are:
libz.so
libz.so.1
When I compile, the linker uses the libz.so as a symlink to point to another .so file.
The .so file which libz.so is pointing to contains an SONAME entry which can be viewed as so:
$ objdump -p ./libz.so | grep SONAME
SONAME libz.so.1
Further I can see that the symlink points to libz.so.1.2.11
$ ls -alh libz.so
lrwxrwxrwx 1 root root 36 May 21 00:51 libz.so -> /lib/x86_64-linux-gnu/libz.so.1.2.11
If I edit the .dynstr section of that library like so:
$ sudo objcopy --dump-section .dynstr=/tmp/dyn.dump ./libz.so.1.2.11
# Find the bytes for libz.so.1 and change them to libz.so.2
$ hexedit /tmp/dyn.dump
$ sudo objcopy --update-section .dynstr=/tmp/dyn.dump ./libz.so.1.2.11
and then recompile my binary I notice:
$ ldd a.out
linux-vdso.so.1 (0x00007ffe54bbe000)
libz.so.2 => not found
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f58bb5c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f58bb7f0000)
Once I create a symlink of libz.so.2 under /lib/x86_64-linux-gnu/libz.so.2 to point to libz.so.1.2.11 I get the following output:
$ ldd a.out
linux-vdso.so.1 (0x00007ffe54bbe000)
libz.so.2 => /lib/x86_64-linux-gnu/libz.so.2 (0x00007f58bb7b9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f58bb5c7000)
/lib64/ld-linux-x86-64.so.2 (0x00007f58bb7f0000)
Therefore to answer my question it is not the symlink which adds an entry in the runtime dependencies of the executable but the SONAME entry in the shared object.

Why won't my compiled c++ binary execute?

So I have just compiled my code and when I try to execute the binary I am getting
-bash: ./a.out: No such file or directory
When I do ldd a.out I see everything is there that I need
ldd a.out
linux-vdso.so.1 (0x00007ffd337fb000)
libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f1200930000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f1200728000)
libncurses.so.5 => /lib/x86_64-linux-gnu/libncurses.so.5 (0x00007f1200505000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007f12002db000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f12000d7000)
libcap.so.2 => /lib/x86_64-linux-gnu/libcap.so.2 (0x00007f11ffed1000)
libnsl.so.1 => /lib/x86_64-linux-gnu/libnsl.so.1 (0x00007f11ffcb7000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f11ff919000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f11ff6fa000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f11ff309000)
/usr/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007f1200b4d000)
Also doing an ls -la shows the file as such
lrwxrwxrwx 1 user user 33 Jul 18 21:26 a.out
Does anyone have any reason why this isn't working?
I am using Ubuntu 18.04.2 LTS.
When I do ldd a.out I see everything is there that I need
No, there isn't.
ldd has been changed to run a known ELF interpreter / dynamic linker instead of the one from the binary's header. You can check that by yourself -- ldd is a shell script on your system.
ldd a.out
...
/usr/lib/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2
And here it's the proof. Do you have a /usr/lib/ld-linux-x86-64.so.2 on your system?
A simpler testcase:
$ echo 'int main(){}' | cc -xc -
$ ./a.out
$ perl -pe 's/ld-linux/ld-LOOOL/' -i ./a.out
$ ./a.out
bash: ./a.out: No such file or directory
$ ldd ./a.out
linux-vdso.so.1 (0x00007ffd707e9000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe936d52000)
/lib64/ld-LOOOL-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x00007fe9372f3000)
As a quick-fix, you can pass the path to an existing interpreter when compiling your program
cc -Wl,-dynamic-linker,/lib64/ld-linux-x86-64.so.2 ...

cannot load shared library which exist on the library search path

I'm trying to execute nft , which was built from source , but it reports
$ nft
nft: error while loading shared libraries: libnftnl.so.4: cannot open shared object file: No such file or directory
I built libmnl,libnftnl,nftables from sources by runnning autogen.sh and then configuring with :
--prefix=/usr/local
these are the contents of /usr/local/lib :
$ ls -l /usr/local/lib/ | grep libnftnl
-rwxr-xr-x 1 root root 961 Mar 2 20:16 libnftnl.la
lrwxrwxrwx 1 root root 17 Mar 2 20:16 libnftnl.so -> libnftnl.so.4.0.0
lrwxrwxrwx 1 root root 17 Mar 2 20:16 libnftnl.so.4 -> libnftnl.so.4.0.0
-rwxr-xr-x 1 root root 913147 Mar 2 20:16 libnftnl.so.4.0.0
more information :
$ ldd $(which nft)
linux-vdso.so.1 => (0x00007ffd7afbf000)
libmnl.so.0 => /usr/lib/x86_64-linux-gnu/libmnl.so.0 (0x00007fc60181f000)
libnftnl.so.4 => not found
libreadline.so.6 => /lib/x86_64-linux-gnu/libreadline.so.6 (0x00007fc6015d8000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fc601364000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fc600f9f000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007fc600d75000)
/lib64/ld-linux-x86-64.so.2 (0x000055a0bd82d000)
and the contents of my ld.so.conf are :
$ cat /etc/ld.so.conf
/usr/lib/x86_64-linux-gnu/libfakeroot
# libc default configuration
/usr/local/lib
/usr/local/lib/
# Multiarch support
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu/mesa-egl
/usr/lib/x86_64-linux-gnu/mesa
/usr/lib/i386-linux-gnu/mesa
# Legacy biarch compatibility support
/lib32
/usr/lib32
# Legacy biarch compatibility support
/libx32
/usr/libx32
But if I set LD_LIBRARY_PATH to '/usr/local/lib' :
$ export LD_LIBRARY_PATH=/usr/local/lib
$ ldd $(which nft)
linux-vdso.so.1 => (0x00007ffedf9b3000)
libmnl.so.0 => /usr/local/lib/libmnl.so.0 (0x00007fb58a033000)
libnftnl.so.4 => /usr/local/lib/libnftnl.so.4 (0x00007fb589e0b000)
libreadline.so.6 => /lib/x86_64-linux-gnu/libreadline.so.6 (0x00007fb589ba3000)
libgmp.so.10 => /usr/lib/x86_64-linux-gnu/libgmp.so.10 (0x00007fb58992f000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fb58956a000)
libmxml.so.1 => /usr/lib/libmxml.so.1 (0x00007fb58935b000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fb58913d000)
libtinfo.so.5 => /lib/x86_64-linux-gnu/libtinfo.so.5 (0x00007fb588f14000)
/lib64/ld-linux-x86-64.so.2 (0x000055a827fb3000)
Can anybody help why it cannot find the library even if it exists in the search path ?
I forgot to run ldconfig , as pointed out by #Petesh . Problem got resolved after runnning ldconfig.

Resources