There is no way to derive the list of libraries needed to resolve undefined symbols in the shared object from the shared object itself. Such a list may or may not exist. It is easy to create a library with an undefined symbol that cannot be resolved by any existing library in the world.
# cat test.c
extern void foo99988776543quzzu();
void test() {
foo99988776543quzzu();
}
# gcc -fPIC -shared -o libtest.so test.c
Here we have created a library with an undefined symbol that no other library in the world can satisfy — until we build one.
# cat foo.c
void foo99988776543quzzu() {}
# gcc -fPIC -shared -o libfoo.so foo.c
No magic in the world can help ldd libtest.so
find libfoo.so. But it is easy to build a loadable, runnable program from libtest.so and libfoo.so.
# cat main.c
extern void test();
int main() { test(); }
# gcc main.c -lfoo -ltest -L. -Wl,-rpath=.
# ./a.out
ldd does not attempt to produce an impossible list of librarirs required to resolve undefined symbols. It does exactly what it says on the tin:
ldd prints the shared objects (shared libraries) required by each program or shared object specified on the command line.
The word "required" here does not mean "required to resolve undefined symbols". As said, a list of objects required to resolve undefined symbols cannot be produced. Instead, "required" means the set of dynamic dependencies, a.k.a. "shared objects required by DT_NEEDED recursively", as detailed in ldd(1) and ld.so(8).
what is the use of ldd at all?
DT_NEEDED sections contain sonames. ldd collects these sonames, recursively, and maps them to file paths using information in DT_RUNPATH, DT_RPATH, LD_LIBRARY_PATH, /etc/ld.so.conf, and whatever places we're searching this week. So the output of ldd
contains a list of file paths for shared objects that will be loaded when the shared object on ldd
command line is loaded. Here's an example:
#ldd ./test
linux-vdso.so.1 (0x00007fff0593f000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007fe7e6776000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fe7e6385000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fe7e5fe7000)
/lib64/ld-linux-x86-64.so.2 (0x00007fe7e6d01000)
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fe7e5dcf000)
This is quite a bunch of useful information even for a most casual of observers. We see that test
appears to be a 64-bit C++ program for x86 Linux built with a relatively recent version of gcc
or a compatible compiler, for example. We also see that it has no third party dependencies.
On the other hand,
# ldd /usr/bin/kdiff3
linux-vdso.so.1 (0x00007ffeeed79000)
libkparts.so.4 => /usr/lib/libkparts.so.4 (0x00007f801a14d000)
libkio.so.5 => /usr/lib/libkio.so.5 (0x00007f8019c9b000)
libkdeui.so.5 => /usr/lib/libkdeui.so.5 (0x00007f8019637000)
libkdecore.so.5 => /usr/lib/libkdecore.so.5 (0x00007f801916b000)
libQtCore.so.4 => /usr/lib/x86_64-linux-gnu/libQtCore.so.4 (0x00007f8018c79000)
libQtGui.so.4 => /usr/lib/x86_64-linux-gnu/libQtGui.so.4 (0x00007f8017f84000)
libstdc++.so.6 => /usr/lib/x86_64-linux-gnu/libstdc++.so.6 (0x00007f8017bfb000)
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f801785d000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f801746c000)
libQtXml.so.4 => /usr/lib/x86_64-linux-gnu/libQtXml.so.4 (0x00007f8017226000)
libQtNetwork.so.4 => /usr/lib/x86_64-linux-gnu/libQtNetwork.so.4 (0x00007f8016ed1000)
libQtSvg.so.4 => /usr/lib/x86_64-linux-gnu/libQtSvg.so.4 (0x00007f8016c78000)
libX11.so.6 => /usr/lib/x86_64-linux-gnu/libX11.so.6 (0x00007f8016940000)
... many more lines ...
lists a lot of dependencies. If it fails to load, we should be able to use the list to figure out the reason. For example, any line that says => not found
would be very helpful.