ldd is the fastest way to see which shared libraries a program needs, but pointing it at the wrong file can execute code you never asked to run. This guide shows a repeatable way to inspect a trusted ELF program's dependencies, read the output that matters, and pick a safer tool the moment a file is not trusted. Allow about ten minutes. You need a shell and the installed ldd command. These checks are read-only and need no elevated privileges.
Examples here were checked with Ubuntu's libc-bin package version 2.39-0ubuntu8.9. The installed command is the glibc ldd script, and the local manpage is from Linux man-pages 6.7. Library paths and hexadecimal addresses vary by machine, so treat those parts of any output as data, not fixed text.
Check which executable your shell will run and record its package version:
$ command -v ldd
/usr/bin/ldd
$ file /usr/bin/ldd
/usr/bin/ldd: Bourne-Again shell script, ASCII text executable
$ dpkg-query -W -f='${Package} ${Version}\n' libc-bin
libc-bin 2.39-0ubuntu8.9
On another distribution, use its package query tool or ldd --version. The useful distinction is between the installed implementation and the general interface the manpage describes. If command -v points into an unexpected project directory, stop and inspect that file before trusting its behaviour.
Checkpoint: you know the path and package version of the ldd you are about to use.
Start with a system executable you trust. /bin/echo is a small, harmless test target:
$ ldd /bin/echo
linux-vdso.so.1 (0x0000...)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000...)
/lib64/ld-linux-x86-64.so.2 (0x0000...)
The addresses above are deliberately abbreviated. On this host the same command printed linux-vdso.so.1, a resolved libc.so.6, and the dynamic linker at /lib64/ld-linux-x86-64.so.2. A line with => gives the library name and the file selected for it. Entries such as linux-vdso.so.1 are special kernel-provided objects, not ordinary files you would find in a library directory.
For a larger trusted program, substitute its absolute path:
$ ldd /usr/bin/PROGRAM_NAME
Replace PROGRAM_NAME with a file you have already identified; do not run that placeholder literally. If the target is not dynamically linked, the command may report not a dynamic executable and return a non-zero status. That is a property of the target, not a reason to add sudo.
In a script, check the exit status rather than searching for one particular library path:
if ldd /bin/echo >/tmp/ldd-echo.txt; then
printf '%s\n' 'Dependency inspection completed'
else
status=$?
printf 'ldd failed with status %s\n' "$status" >&2
exit "$status"
fi
sed -n '1,8p' /tmp/ldd-echo.txt
rm -f /tmp/ldd-echo.txt
The temporary file holds only output from this trusted probe and is safe to remove once you have looked at it. That final rm is just cleanup, not a change to the executable or its libraries.
Use verbose mode when the ordinary list is not enough:
$ ldd --verbose /bin/echo
$ ldd -v /bin/echo
--verbose and -v add extra detail such as symbol-versioning information. Output gets longer and can include loader-specific noise, so save it when comparing two environments:
ldd --verbose /bin/echo > /tmp/echo-ldd.txt
sed -n '1,30p' /tmp/echo-ldd.txt
--data-relocs or -d: performs data relocations and reports missing objects.--function-relocs or -r: includes function relocations too.$ ldd --data-relocs /bin/echo
$ ldd --function-relocs /bin/echo
Both are for ELF files, and both can surface missing objects or functions a plain dependency listing would miss. Run them only on a trusted target: they still involve the dynamic-linking machinery and are not a sanitiser for hostile files.
Checkpoint: choose the least detailed mode that answers the question. Plain ldd is normally enough for a missing-library investigation; -v, -d and -r are diagnostic extensions on top.
Warning: do not run ldd on an executable or shared object from an untrusted source. In some circumstances, ldd may execute code through the file's ELF interpreter while trying to obtain dependency information, and the local manpage specifically warns that this can result in arbitrary code execution. A file being named program, ending in .so, or coming from a familiar-looking location does not make it trusted.
This is security-sensitive. Do not try to make it safe with sudo, a container, or an environment variable: privilege can increase the impact of code that runs, and loader environment variables can change dependency resolution rather than contain it.
For an untrusted ELF file, inspect its direct DT_NEEDED entries with objdump instead:
$ objdump -p /path/to/untrusted-file | grep NEEDED
NEEDED libc.so.6
Replace /path/to/untrusted-file with the exact file under investigation. This reads the file's metadata without asking the dynamic linker to resolve and load its dependency tree, so it only reports direct dependencies, whereas ldd normally shows the whole tree. That difference matters: objdump is the safer first view, not a drop-in replacement for every diagnostic question.
On the checked host, a trusted comparison produced this direct entry:
$ objdump -p /bin/echo | grep NEEDED
NEEDED libc.so.6
If objdump cannot identify the file as an object type it understands, keep the error and investigate the file type. Do not fall back to ldd just to force an answer out of it.
A missing path is an input error. This command does not search for a replacement:
$ ldd /tmp/ldd-does-not-exist
ldd: /tmp/ldd-does-not-exist: No such file or directory
Check the path with ls -l and use an absolute path if the working directory might be unclear. A non-zero status from ldd is useful evidence: preserve it in automation.
An output line containing not found means the loader's search rules failed to locate a required object. Record the complete path, architecture and relevant loader configuration before changing anything. Do not copy a random library into /usr/lib or set LD_LIBRARY_PATH globally: those actions can change which code a process loads and can break unrelated programs elsewhere on the box. If a service is affected, test any library-path change in its own controlled environment and keep a rollback of the original service configuration.
--unused or -u reports unused direct dependencies when the installed implementation supports it. The local manpage dates this option to glibc 2.3.4, but the result is a diagnostic hint, not permission to delete a library or edit a package-managed binary. Remove no package as part of this guide.
ldd executable and package version are installed.-v, -d and -r add useful diagnostic detail.objdump -p ... | grep NEEDED as the safer first view.