Shared libraries are central to how applications run on Linux, and checking their dependencies helps diagnose startup failures and subtle runtime bugs. When a required .so file is missing or mismatched, an otherwise valid binary can refuse to start with errors about loading shared libraries.
Most dynamically linked ELF binaries list their required libraries in their metadata, and the dynamic loader (commonly /lib64/ld-linux-x86-64.so.2) locates those libraries in search paths such as /lib, /usr/lib, and any locations derived from rpath, runpath, or environment variables. Tools like ldd, readelf, and process-introspection commands expose this information directly from the binary or from a running process.
Commands shown here target typical Linux systems using the standard glibc runtime and work for both executables and shared objects. Output formats and library paths vary between distributions and architectures, and running ldd on untrusted binaries can be unsafe because it may execute code as part of the loading process. Before changing or installing libraries based on this information, backups and change control help avoid breaking other applications that rely on the same .so files.
A typical failure caused by a missing shared library resembles the following example when a command tries to load an absent .so file.
$ sudo dpkg sudo: error while loading shared libraries: libpthread.so.0: cannot open shared object file: No such file or directory
$ which bash /usr/bin/bash
$ ldd /usr/bin/bash linux-vdso.so.1 (0x0000ffff884bc000) libtinfo.so.6 => /lib/aarch64-linux-gnu/libtinfo.so.6 (0x0000ffff88290000) libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffff880d0000) /lib/ld-linux-aarch64.so.1 (0x0000ffff88480000)
The ldd command shows all shared libraries required by a program and the resolved path to each .so file.
Running ldd on untrusted executables can be unsafe because it may cause code execution through crafted runtime loaders or environment settings.
$ ldd --verbose /usr/bin/bash linux-vdso.so.1 (0x0000ffffa23df000) libtinfo.so.6 => /lib/aarch64-linux-gnu/libtinfo.so.6 (0x0000ffffa21a0000) libc.so.6 => /lib/aarch64-linux-gnu/libc.so.6 (0x0000ffffa1fe0000) /lib/ld-linux-aarch64.so.1 (0x0000ffffa2390000) Version information: /usr/bin/bash: ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1 libtinfo.so.6 (NCURSES6_TINFO_5.0.19991023) => /lib/aarch64-linux-gnu/libtinfo.so.6 libc.so.6 (GLIBC_2.25) => /lib/aarch64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.38) => /lib/aarch64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.33) => /lib/aarch64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.36) => /lib/aarch64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.34) => /lib/aarch64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6 /lib/aarch64-linux-gnu/libtinfo.so.6: ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1 libc.so.6 (GLIBC_2.33) => /lib/aarch64-linux-gnu/libc.so.6 libc.so.6 (GLIBC_2.17) => /lib/aarch64-linux-gnu/libc.so.6 /lib/aarch64-linux-gnu/libc.so.6: ld-linux-aarch64.so.1 (GLIBC_PRIVATE) => /lib/ld-linux-aarch64.so.1 ld-linux-aarch64.so.1 (GLIBC_2.17) => /lib/ld-linux-aarch64.so.1 ##### snipped #####
More options for ldd:
$ ldd --help
Usage: ldd [OPTION]... FILE...
--help print this help and exit
--version print version information and exit
-d, --data-relocs process data relocations
-r, --function-relocs process data and function relocations
-u, --unused print unused direct dependencies
-v, --verbose print all information
For bug reporting instructions, please see:
<https://bugs.launchpad.net/ubuntu/+source/glibc/+bugs>.
$ readelf --dynamic /usr/bin/bash | grep NEEDED 0x0000000000000001 (NEEDED) Shared library: [libtinfo.so.6] 0x0000000000000001 (NEEDED) Shared library: [libc.so.6] 0x0000000000000001 (NEEDED) Shared library: [ld-linux-aarch64.so.1]
The NEEDED entries show the .so names recorded in the binary, independent of how the dynamic loader resolves them on the system.
$ awk '/\.so/{print $6}' /proc/$(pgrep bash | head -n1)/maps | sort -u
/usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
/usr/lib/aarch64-linux-gnu/libc.so.6
/usr/lib/aarch64-linux-gnu/libtinfo.so.6.4
$ lsof -p $(pgrep bash | head -n1) | grep mem bash 21178 root mem REG 0,64 1722920 69073 /usr/lib/aarch64-linux-gnu/libc.so.6 bash 21178 root mem REG 0,64 265416 70519 /usr/lib/aarch64-linux-gnu/libtinfo.so.6.4 bash 21178 root mem REG 0,64 203968 68993 /usr/lib/aarch64-linux-gnu/ld-linux-aarch64.so.1
pgrep bash | head -n1 selects the first matching process ID for bash and passes it to lsof.
$ pmap $(pgrep bash | head -n1) | tail -n +2 | grep \.so | awk '{ print $4 }' | sort -u
ld-linux-aarch64.so.1
libc.so.6
libtinfo.so.6.4
$ sudo dpkg --help Usage: dpkg [<option>...] <command> Commands: -i|--install <.deb file name>... | -R|--recursive <directory>... --unpack <.deb file name>... | -R|--recursive <directory>... -A|--record-avail <.deb file name>... | -R|--recursive <directory>... --configure <package>... | -a|--pending ##### snipped #####