Ldd
Ldd is a utility that displays shared library dependencies for executable files and shared libraries. This guide covers analyzing dynamic dependencies, managing library paths, linker configuration, and troubleshooting missing libraries.
Basic Usage
Listing Dependencies
# Display dependencies for executable
ldd /bin/bash
# List dependencies for a library
ldd /lib/x86_64-linux-gnu/libc.so.6
# Display dependencies for binary in PATH
ldd /usr/bin/python3
# Show dependencies with symbol addresses
ldd /bin/ls
# Display dependencies for shared library
ldd /usr/lib/x86_64-linux-gnu/libssl.so
Basic Command Syntax
# Standard ldd usage
ldd [options] file
# Common options
ldd -v /bin/bash # Verbose output (shows version symbols)
ldd -r /bin/bash # Check for unused objects
ldd -u /bin/bash # Check for undefined symbols
ldd -d /bin/bash # Report missing objects (data relocations)
ldd -V /bin/bash # Show version information
ldd --help # Display help message
Understanding Ldd Output
Typical Output Example
$ ldd /bin/bash
linux-vdso.so.1 (0x00007fff53ffe000)
libtinfo.so.6 => /lib/x86_64-linux-gnu/libtinfo.so.6 (0x00007f8e6a000000)
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f8e69dfc000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f8e69c04000)
/lib64/ld-linux-x86-64.so.2 (0x00007f8e6a1c8000)
Output Components
# Memory address in hexadecimal
(0x00007fff53ffe000)
# Library name
libtinfo.so.6
# Arrow indicates linked path (=> shows actual path if different)
=>
# Absolute path to the library file
/lib/x86_64-linux-gnu/libtinfo.so.6
# Virtual library (provided by kernel)
linux-vdso.so.1
# Dynamic linker/loader
/lib64/ld-linux-x86-64.so.2
# Not found error (when library missing)
libc.so.6 => not found
Dependency Analysis
Checking for Missing Libraries
# Check for missing dependencies
ldd /bin/bash | grep "not found"
# Show detailed missing libraries
ldd -d /usr/bin/some-binary
# Check for undefined symbols
ldd -u /bin/bash
# Force checking immediate binding
ldd -r /bin/bash
# Verbose output with all symbols
ldd -v /bin/bash | head -20
Analyzing Complex Dependencies
# Show all dependencies recursively (requires manual traversal)
ldd /usr/bin/python3
ldd /usr/lib/x86_64-linux-gnu/libpython3.9.so.1.0
# Count total dependencies
ldd /bin/bash | wc -l
# Find all binaries depending on specific library
for binary in /usr/bin/*; do
ldd "$binary" 2>/dev/null | grep -q "libssl" && echo "$binary"
done
# List libraries with version info
ldd -v /bin/bash | grep "=>.*GLIBC"
Finding Version Information
# Show symbol versions with verbose flag
ldd -v /bin/bash
# Display version requirements
objdump -T /bin/bash | grep -i version
# Show ABI compatibility information
readelf -V /bin/bash
Library Paths
Default Library Search Paths
# Display default library path from ld.so configuration
ld --verbose | grep SEARCH_DIR | head -1
# System library directories
/lib
/lib64
/usr/lib
/usr/lib64
/usr/local/lib
/usr/local/lib64
# 32-bit libraries on 64-bit systems
/lib32
/usr/lib32
Custom Library Paths
# Using LD_LIBRARY_PATH environment variable
export LD_LIBRARY_PATH=/opt/custom/lib:/usr/local/lib:$LD_LIBRARY_PATH
# Verify path is used
ldd /bin/bash | grep custom
# Temporary override for single command
LD_LIBRARY_PATH=/opt/lib:/usr/lib ldd /bin/bash
# Prepend to default paths (safer)
export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH
# Append to default paths
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/lib64
# Check current LD_LIBRARY_PATH
echo $LD_LIBRARY_PATH
Dynamic Linker Configuration
/etc/ld.so.conf Configuration
# View main linker configuration
cat /etc/ld.so.conf
# Display all configuration files
cat /etc/ld.so.conf
cat /etc/ld.so.conf.d/*.conf
# Typical content
/usr/local/lib
/usr/local/lib64
include /etc/ld.so.conf.d/*.conf
Managing Linker Cache
# Update linker cache (must run after changing ld.so.conf)
sudo ldconfig
# Run ldconfig in verbose mode
sudo ldconfig -v | head -20
# Display linker cache contents
ldconfig -p | head -20
# Display cache in specific directory
ldconfig -p | grep "/opt"
# Check if library is in cache
ldconfig -p | grep "libcustom"
# Print library name and real path
ldconfig -p | grep libc.so.6
Custom Library Configuration
# Create custom configuration file
sudo nano /etc/ld.so.conf.d/custom.conf
# Add custom paths
/opt/myapp/lib
/usr/local/custom/lib
# Save file and update cache
sudo ldconfig
# Verify new paths are cached
ldconfig -p | grep "/opt/myapp"
Advanced Analysis
Using objdump for Symbols
# Display all dynamic symbols
objdump -T /bin/bash | head -20
# Show imported symbols
objdump -T /bin/bash | grep UND
# Display symbol versions
objdump -T /bin/bash | grep "@@"
# Show library relocations
objdump -R /bin/bash
# Count imported functions
objdump -T /bin/bash | grep UND | wc -l
# Find version requirements for specific symbol
objdump -T /bin/bash | grep GLIBC_2.17
Using readelf for ELF Analysis
# Display dynamic section
readelf -d /bin/bash | grep NEEDED
# Show dynamic symbol table
readelf -s /bin/bash | head -20
# Display version symbols
readelf -V /bin/bash
# Show program headers
readelf -l /bin/bash | grep INTERP
# Display all dynamic information
readelf -d /bin/bash
Common Scenarios
Static vs Dynamic Linking
# Check if binary is statically linked
ldd /bin/static_binary 2>&1 | grep "not a dynamic executable"
# Dynamically linked binary (normal case)
ldd /bin/bash
# Comparison
file /bin/bash
# output: ELF 64-bit LSB executable, dynamically linked
file /bin/busybox
# output: ELF 64-bit LSB executable, statically linked
Finding Library Locations
# Find library file for dependency
find /usr -name "libc.so.6" 2>/dev/null
# Use ldconfig to locate
ldconfig -p | grep libc.so.6
# Check library version
strings /lib/x86_64-linux-gnu/libc.so.6 | grep "GLIBC"
# Locate alternative versions
find /usr -name "libc-*.so" 2>/dev/null
# Check real path (resolves symlinks)
ls -l /lib/x86_64-linux-gnu/libc.so.6
# Display file info
file /lib/x86_64-linux-gnu/libc.so.6
Troubleshooting Dependency Issues
# Binary not finding library
ldd /bin/myapp | grep "not found"
# Add library path and recheck
export LD_LIBRARY_PATH=/opt/lib:$LD_LIBRARY_PATH
ldd /bin/myapp | grep "not found"
# Update system cache if installed to standard path
sudo ldconfig
# Check library version compatibility
ldd -v /bin/myapp | grep "=>"
# Verify library is executable
file /lib/x86_64-linux-gnu/libc.so.6
# Check library symbols
strings /lib/x86_64-linux-gnu/libc.so.6 | grep "GLIBC_2"
Library Version Management
Checking GLIBC Version
# Display GLIBC version
ldd --version
# Show in detail
strings /lib/x86_64-linux-gnu/libc.so.6 | grep "GLIBC_"
# Count available versions
strings /lib/x86_64-linux-gnu/libc.so.6 | grep "GLIBC_" | sort -u | wc -l
# Find minimum GLIBC required by binary
objdump -T /bin/bash | grep "GLIBC" | awk '{print $NF}' | sort -u
Handling Multiple Library Versions
# List available library versions
ls -la /lib/x86_64-linux-gnu/libc*
# Check symlink resolution
readlink /lib/x86_64-linux-gnu/libc.so.6
# Verify correct version is used
ldd -v /bin/bash | grep libc.so
# Override for testing
LD_LIBRARY_PATH=/opt/experimental/lib:$LD_LIBRARY_PATH ldd /bin/bash
Performance and Debugging
Profiling Library Loading
# Show library load order and timing
strace -e openat ldd /bin/bash 2>&1 | grep ".so"
# Debug symbol resolution
ldd -v /bin/bash 2>&1 | grep -A 5 "Symbol table"
# Trace linker operations
LD_DEBUG=all /bin/bash -c "echo test" 2>&1 | head -30
# Debug specific categories
LD_DEBUG=libs /bin/bash -c "echo test" 2>&1 | head -20
# Verbose linker information
LD_DEBUG=symbols /bin/bash -c "echo test" 2>&1 | head -20
Reducing Dependencies
# Find unused libraries (if supported by binary)
ldd -u /usr/bin/python3
# Show relocations that might not be needed
objdump -R /bin/bash | head -10
# Test if library can be removed (dangerous!)
LD_PRELOAD=/nonexistent.so /bin/bash -c "echo test"
# Check for lazy binding
readelf -d /bin/bash | grep BIND
Security Considerations
Verifying Library Integrity
# Check for library modifications
md5sum /lib/x86_64-linux-gnu/libc.so.6
# Verify against package database (Debian)
sudo debsums -c /libc6
# Display library checksums
sha256sum /lib/x86_64-linux-gnu/libc.so.6
# Compare with package manifest
dpkg -L libc6 | grep libc.so.6
Preventing Library Injection
# Check for LD_PRELOAD usage
env | grep LD_
# Unset potentially dangerous variables before running
unset LD_PRELOAD
unset LD_LIBRARY_PATH
/bin/bash
# Run with minimal environment
env -i /bin/bash -c "ldd /bin/bash"
# Securely check dependencies
strace -e open,openat /bin/bash -c "echo test" 2>&1 | grep ".so"
Practical Examples
Complete Application Analysis
#!/bin/bash
# Analyze all dependencies for an application
APP="/usr/bin/python3"
echo "=== Direct Dependencies ==="
ldd "$APP" | grep "=>"
echo "=== Missing Libraries ==="
ldd "$APP" 2>&1 | grep "not found" || echo "All dependencies found"
echo "=== Version Requirements ==="
ldd -v "$APP" 2>&1 | grep "GLIBC" | head -5
echo "=== Library Paths Used ==="
ldd "$APP" | awk '{print $3}' | sort -u
echo "=== Total Dependencies ==="
ldd "$APP" | wc -l
Finding Incompatible Dependencies
#!/bin/bash
# Check binary for unmet dependencies
BINARY="$1"
if [ -z "$BINARY" ]; then
echo "Usage: $0 <binary>"
exit 1
fi
echo "Checking dependencies for $BINARY..."
ldd "$BINARY" | grep -i "not found"
if [ $? -eq 1 ]; then
echo "All dependencies resolved"
else
echo "ERROR: Missing dependencies detected"
exit 1
fi
Linker Configuration Script
#!/bin/bash
# Add custom library path to system configuration
NEW_PATH="/opt/myapp/lib"
if ! grep -q "$NEW_PATH" /etc/ld.so.conf.d/*; then
echo "Adding $NEW_PATH to linker configuration..."
echo "$NEW_PATH" | sudo tee -a /etc/ld.so.conf.d/custom.conf > /dev/null
echo "Updating linker cache..."
sudo ldconfig
echo "Verifying..."
ldconfig -p | grep "$NEW_PATH"
else
echo "$NEW_PATH already configured"
fi
Troubleshooting
Common Issues
# Issue: "GLIBCXX_3.4.21 not found"
# Solution: Update libstdc++
sudo apt install libstdc++6
# Issue: "libc.so.6: version `GLIBC_2.29' not found"
# Solution: Update glibc (risky - be careful)
sudo apt install libc6
# Issue: Library in custom path not found
# Solution: Update ld.so.conf and run ldconfig
echo "/opt/lib" | sudo tee -a /etc/ld.so.conf.d/custom.conf
sudo ldconfig
# Issue: "cannot execute binary file"
# Solution: Check architecture
file /path/to/binary
ldd /path/to/binary
Debugging Library Loading
# Enable linker debugging
export LD_DEBUG=all
/bin/bash -c "ldd /bin/bash" 2>&1 | grep "binding"
# Check specific library
export LD_DEBUG=libs
/bin/bash -c "echo test" 2>&1 | grep "libc"
# Show relocations
export LD_DEBUG=reloc
/bin/bash -c "echo test" 2>&1 | head -30
# Disable to restore normal operation
unset LD_DEBUG
Resources
Last updated: 2025-03-30