I want to find out the list of dynamic libraries a binary loads when run (With their full paths). I am using CentOS 6.0. How to do this?
9 Answers
You can do this with ldd
command:
NAME
ldd - print shared library dependencies
SYNOPSIS
ldd [OPTION]... FILE...
DESCRIPTION
ldd prints the shared libraries required by each program or shared
library specified on the command line.
....
Example:
$ ldd /bin/ls
linux-vdso.so.1 => (0x00007fff87ffe000)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007ff0510c1000)
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007ff050eb9000)
libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007ff050cb0000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ff0508f0000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007ff0506ec000)
/lib64/ld-linux-x86-64.so.2 (0x00007ff0512f7000)
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007ff0504ce000)
libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007ff0502c9000)
-
2Any idea of what would be a macOS equivalent of this? No
lld
on darwin, it appears, nor can I find it via homebrew.– mz2Oct 23, 2016 at 14:05 -
18
-
11be aware that this may execute the binary. So if the binary is untrusted, it may be better to not use
ldd
. See man page. Aug 19, 2019 at 2:57 -
4To follow @PaulRooney 's comment: In particular, the man page suggests using
objdump -p /path/to/program | grep NEEDED
as an alternative to ldd if you do not trust the executable. Apr 4, 2020 at 21:56 -
1
lddtree
frompax-utils
is better when you want to see the hierarchical tree of dependencies including dependencies' dependencies; plainldd
shows only the immediate dependencies. Oct 18, 2021 at 10:57
readelf -d $executable | grep 'NEEDED'
Can be used if you can't run the executable, e.g. if it was cross compiled, or if you don't trust it:
In the usual case, ldd invokes the standard dynamic linker (see ld.so(8)) with the LD_TRACE_LOADED_OBJECTS environment variable set to 1, which causes the linker to display the library dependencies. Be aware, however, that in some circumstances, some versions of ldd may attempt to obtain the dependency information by directly executing the program. Thus, you should never employ ldd on an untrusted executable, since this may result in the execution of arbitrary code.
Example:
readelf -d /bin/ls | grep 'NEEDED'
Sample ouptut:
0x0000000000000001 (NEEDED) Shared library: [libselinux.so.1]
0x0000000000000001 (NEEDED) Shared library: [libacl.so.1]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
Note that libraries can depend on other libraries, so now you need to find the dependencies.
A naive approach that often works is:
$ locate libselinux.so.1
/lib/i386-linux-gnu/libselinux.so.1
/lib/x86_64-linux-gnu/libselinux.so.1
/mnt/debootstrap/lib/x86_64-linux-gnu/libselinux.so.1
but the more precise method is to understand the ldd
search path / cache. I think ldconfig
is the way to go.
Choose one, and repeat:
readelf -d /lib/x86_64-linux-gnu/libselinux.so.1 | grep 'NEEDED'
Sample output:
0x0000000000000001 (NEEDED) Shared library: [libpcre.so.3]
0x0000000000000001 (NEEDED) Shared library: [libdl.so.2]
0x0000000000000001 (NEEDED) Shared library: [libc.so.6]
0x0000000000000001 (NEEDED) Shared library: [ld-linux-x86-64.so.2]
And so on.
See also:
- Determine direct shared object dependencies of a Linux binary? | Stack Overflow
- How can I find the dynamic libraries required by an ELF Binary in C++? | Stack Overflow
- How to know which dynamic libraries are needed by an ELF? | Stack Overflow
/proc/<pid>/maps
for running processes
Mentioned by Basile, this is useful to find all the libraries currently being used by running executables. E.g.:
sudo awk '/\.so/{print $6}' /proc/1/maps | sort -u
shows all currently loaded dynamic dependencies of init
(PID 1
):
/lib/x86_64-linux-gnu/ld-2.23.so
/lib/x86_64-linux-gnu/libapparmor.so.1.4.0
/lib/x86_64-linux-gnu/libaudit.so.1.0.0
/lib/x86_64-linux-gnu/libblkid.so.1.1.0
/lib/x86_64-linux-gnu/libc-2.23.so
/lib/x86_64-linux-gnu/libcap.so.2.24
/lib/x86_64-linux-gnu/libdl-2.23.so
/lib/x86_64-linux-gnu/libkmod.so.2.3.0
/lib/x86_64-linux-gnu/libmount.so.1.1.0
/lib/x86_64-linux-gnu/libpam.so.0.83.1
/lib/x86_64-linux-gnu/libpcre.so.3.13.2
/lib/x86_64-linux-gnu/libpthread-2.23.so
/lib/x86_64-linux-gnu/librt-2.23.so
/lib/x86_64-linux-gnu/libseccomp.so.2.2.3
/lib/x86_64-linux-gnu/libselinux.so.1
/lib/x86_64-linux-gnu/libuuid.so.1.3.0
This method also shows libraries opened with dlopen
, tested with this minimal setup hacked up with a sleep(1000)
on Ubuntu 18.04.
See also: How to see the currently loaded shared objects in Linux? | Super User
-
4Nice part about readelf method is that it works on cross-binaries (ex: armhf on amd64) as well Aug 20, 2019 at 2:21
-
2+1 for deep diving into elf binary itself rather than relying on linker or other tools. Feb 27, 2020 at 16:58
-
1
ldd and lsof show the libraries loaded either directly or at a given moment. They do not account for libraries loaded via dlopen
(or discarded by dlclose
). You can get a better picture of this using strace
, e.g.,
strace -e trace=open myprogram
(since dlopen
ultimately calls open
- though you may of course have a system using different names for 64-bit opens...).
Example:
strace -e trace=open date
shows me this:
open("/etc/ld.so.cache", O_RDONLY) = 3
open("/lib/x86_64-linux-gnu/librt.so.1", O_RDONLY) = 3
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY) = 3
open("/lib/x86_64-linux-gnu/libpthread.so.0", O_RDONLY) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY) = 3
open("/etc/localtime", O_RDONLY) = 3
Wed Apr 12 04:56:32 EDT 2017
from which one could grep the ".so" names to just see shared objects.
-
11
-
Nice method.
/proc/<pid>/maps
also showsdlopen
libs btw: unix.stackexchange.com/questions/120015/…ltrace -S
output is even cooler as it shows both syscalls and library calls likedlopen
: unix.stackexchange.com/questions/226524/… Sep 13, 2018 at 21:27
lsof also can show you which libraries are being used for one particular process.
i.e.
$ pidof nginx
6920 6919
$ lsof -p 6919|grep mem
nginx 6919 root mem REG 0,64 65960 43 /lib64/libnss_files-2.12.so
nginx 6919 root mem REG 0,64 19536 36 /lib64/libdl-2.12.so
nginx 6919 root mem REG 0,64 10312 1875 /lib64/libfreebl3.so
nginx 6919 root mem REG 0,64 1923352 38 /lib64/libc-2.12.so
nginx 6919 root mem REG 0,64 88600 1034 /lib64/libz.so.1.2.3
nginx 6919 root mem REG 0,64 1967392 1927 /usr/lib64/libcrypto.so.1.0.1e
nginx 6919 root mem REG 0,64 183080 1898 /lib64/libpcre.so.0.0.1
nginx 6919 root mem REG 0,64 40400 1217 /lib64/libcrypt-2.12.so
nginx 6919 root mem REG 0,64 142688 77 /lib64/libpthread-2.12.so
nginx 6919 root mem REG 0,64 154664 31 /lib64/ld-2.12.so
For mass query:
create a small script (
useslib
) and put in in the PATH (orspecify a full path in the command below)#! /bin/bash ldd $1 | grep -q $2 exit $?
Use it in a
find
command, for instance:find /usr/bin/ -executable -type f -exec useslib {} libgtk-x11-2.0 \; -print
(libgtk-x11-2.0 seems to be the gtk2 lib)
For a process of pid 1234, you could also read the /proc/1234/maps
(textual) pseudo-file (read proc(5)...) or use pmap(1)
This gives the virtual address space of that process, hence the files (including shared libraries, even dlopen(3)-ed one) which are memory mapped
(of course, use ps aux
or pgrep(1) to find the processes running some given program)
It is possible use pmap
.
For example, start a process: $ watch date
Get pid: $ ps -ef | grep watch
Show memory map: $ pmap <pid>
Show with full path: $ pmap <pid> -p
$ pmap 72770
72770: watch date
00005613a32c9000 20K r-x-- watch
00005613a34cd000 4K r---- watch
00005613a34ce000 4K rw--- watch
00005613a4f6a000 264K rw--- [ anon ]
00007f2f3a7d5000 204616K r---- locale-archive
00007f2f46fa7000 1748K r-x-- libc-2.27.so
00007f2f4715c000 2048K ----- libc-2.27.so
00007f2f4735c000 16K r---- libc-2.27.so
00007f2f47360000 8K rw--- libc-2.27.so
00007f2f47362000 16K rw--- [ anon ]
00007f2f47366000 12K r-x-- libdl-2.27.so
00007f2f47369000 2044K ----- libdl-2.27.so
00007f2f47568000 4K r---- libdl-2.27.so
00007f2f47569000 4K rw--- libdl-2.27.so
00007f2f4756a000 160K r-x-- libtinfo.so.6.1
00007f2f47592000 2048K ----- libtinfo.so.6.1
00007f2f47792000 16K r---- libtinfo.so.6.1
00007f2f47796000 4K rw--- libtinfo.so.6.1
00007f2f47797000 232K r-x-- libncursesw.so.6.1
00007f2f477d1000 2048K ----- libncursesw.so.6.1
00007f2f479d1000 4K r---- libncursesw.so.6.1
00007f2f479d2000 4K rw--- libncursesw.so.6.1
00007f2f479d3000 148K r-x-- ld-2.27.so
00007f2f47bdb000 20K rw--- [ anon ]
00007f2f47bf1000 28K r--s- gconv-modules.cache
00007f2f47bf8000 4K r---- ld-2.27.so
00007f2f47bf9000 4K rw--- ld-2.27.so
00007f2f47bfa000 4K rw--- [ anon ]
00007ffd39404000 136K rw--- [ stack ]
00007ffd3959b000 12K r---- [ anon ]
00007ffd3959e000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
total 215692K
$ pmap 72770 -p
72770: watch date
00005613a32c9000 20K r-x-- /usr/bin/watch
00005613a34cd000 4K r---- /usr/bin/watch
00005613a34ce000 4K rw--- /usr/bin/watch
00005613a4f6a000 264K rw--- [ anon ]
00007f2f3a7d5000 204616K r---- /usr/lib/locale/locale-archive
00007f2f46fa7000 1748K r-x-- /usr/lib64/libc-2.27.so
00007f2f4715c000 2048K ----- /usr/lib64/libc-2.27.so
00007f2f4735c000 16K r---- /usr/lib64/libc-2.27.so
00007f2f47360000 8K rw--- /usr/lib64/libc-2.27.so
00007f2f47362000 16K rw--- [ anon ]
00007f2f47366000 12K r-x-- /usr/lib64/libdl-2.27.so
00007f2f47369000 2044K ----- /usr/lib64/libdl-2.27.so
00007f2f47568000 4K r---- /usr/lib64/libdl-2.27.so
00007f2f47569000 4K rw--- /usr/lib64/libdl-2.27.so
00007f2f4756a000 160K r-x-- /usr/lib64/libtinfo.so.6.1
00007f2f47592000 2048K ----- /usr/lib64/libtinfo.so.6.1
00007f2f47792000 16K r---- /usr/lib64/libtinfo.so.6.1
00007f2f47796000 4K rw--- /usr/lib64/libtinfo.so.6.1
00007f2f47797000 232K r-x-- /usr/lib64/libncursesw.so.6.1
00007f2f477d1000 2048K ----- /usr/lib64/libncursesw.so.6.1
00007f2f479d1000 4K r---- /usr/lib64/libncursesw.so.6.1
00007f2f479d2000 4K rw--- /usr/lib64/libncursesw.so.6.1
00007f2f479d3000 148K r-x-- /usr/lib64/ld-2.27.so
00007f2f47bdb000 20K rw--- [ anon ]
00007f2f47bf1000 28K r--s- /usr/lib64/gconv/gconv-modules.cache
00007f2f47bf8000 4K r---- /usr/lib64/ld-2.27.so
00007f2f47bf9000 4K rw--- /usr/lib64/ld-2.27.so
00007f2f47bfa000 4K rw--- [ anon ]
00007ffd39404000 136K rw--- [ stack ]
00007ffd3959b000 12K r---- [ anon ]
00007ffd3959e000 8K r-x-- [ anon ]
ffffffffff600000 4K r-x-- [ anon ]
total 215692K
i don't know how widespread the -p
option to ldconfig(8), but the following sh/awk script, using the readelf(1) suggestion, and ldconfig's -p
, might be of help if you want to avoid any security issues with ldd(1), but also see the path of the dynamic libraries. (NB: this does not do the transitive closure of inclusion, as it were, so you only see the libraries called out directly by the a.out.)
#!/usr/bin/env bash
needs=`readelf -d $1 | \
awk '$2=="(NEEDED)" {
gsub("[][]", "", $5);
hits[$5]=$5
}
END {
for (i in hits) {
printf(sprintf("%s ", i))
}
}'`
ldconfig -p | \
awk -vneeds="$needs" \
'BEGIN{
split(needs,aneeds)
}
{
if (!arr[$1])
arr[$1] = $NF
}
END {
for (i in aneeds) {
need = aneeds[i];
if (arr[need]) {
print need "\t" arr[need]
} else {
print "unfulfilled:", need
}
}
}'
for example:
{1001} ./foo.sh a.out
libc.so.6 /usr/lib/libc.so.6
libX11.so.6 /usr/lib/libX11.so.6
libgdk-3.so.0 /usr/lib/libgdk-3.so.0
libgcr-base-3.so.1 /usr/lib/libgcr-base-3.so.1
libjavascriptcoregtk-4.0.so.18 /usr/local/lib/libjavascriptcoregtk-4.0.so.18
libatk-1.0.so.0 /usr/lib/libatk-1.0.so.0
libharfbuzz.so.0 /usr/lib/libharfbuzz.so.0
libsoup-2.4.so.1 /usr/lib/libsoup-2.4.so.1
libgdk_pixbuf-2.0.so.0 /usr/lib/libgdk_pixbuf-2.0.so.0
libgck-1.so.0 /usr/lib/libgck-1.so.0
libgthread-2.0.so.0 /usr/lib/libgthread-2.0.so.0
libgcr-ui-3.so.1 /usr/lib/libgcr-ui-3.so.1
libglib-2.0.so.0 /usr/lib/libglib-2.0.so.0
libgobject-2.0.so.0 /usr/lib/libgobject-2.0.so.0
libcairo-gobject.so.2 /usr/lib/libcairo-gobject.so.2
libpango-1.0.so.0 /usr/lib/libpango-1.0.so.0
libz.so.1 /usr/lib/libz.so.1
libgio-2.0.so.0 /usr/lib/libgio-2.0.so.0
libpangocairo-1.0.so.0 /usr/lib/libpangocairo-1.0.so.0
libp11-kit.so.0 /usr/lib/libp11-kit.so.0
libcairo.so.2 /usr/lib/libcairo.so.2
libgtk-3.so.0 /usr/lib/libgtk-3.so.0
libwebkit2gtk-4.0.so.37 /usr/local/lib/libwebkit2gtk-4.0.so.37
I found lddtree
from PaX-utils (package name pax-utils
on most distros) to be more useful; it prints a hierarchical tree of dependencies (including dependencies' dependencies). This is better than ldd
which only lists the binary's immediate dependencies.
lddtree $(which ls)
ls => /usr/bin/ls (interpreter => /lib64/ld-linux-x86-64.so.2)
libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1
libpcre2-8.so.0 => /lib/x86_64-linux-gnu/libpcre2-8.so.0
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2
ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
lddtree
by default skips duplicate dependencies; if you also want that pass -a
; be ready to tolerate the redundancy and verbosity.