3

I'd like to know what exactly ldd does. Does it print only libraries from DT_NEEDED structures of .dynamic section? This is not a complete list of libraries that are required to resolve all undefined symbols of ldd's input library, as far as I know. In this case, what is the use of ldd at all?

Or does it really list all the libraries the ldd's input library actually depends on?

This is not a question about whether ldd shows dependencies of dependencies - this is a question about whether libraries reported by ldd resolve all the undefined symbols of ldd's input library.

Alexey
  • 710
  • 3
  • 7
  • 19

3 Answers3

4

Does ldd print only libraries from DT_NEEDED structures of .dynamic section?

No, that is what readelf --dynamic does.

what is the use of ldd at all?

ldd shows what libraries the runtime linker ld.so loads when starting your executable or loading a shared library. This is a recursive process, e.g. an executable needs a shared library (DT_NEEDED), so that library gets loaded. Then it proceeds to load the dependencies of the loaded library (DT_NEEDED) and so on.

You don't necessarily need ldd, you can just set LD_DEBUG=all environment variable to make ld.so print that information and more. See man ld.so for more information.

Each loaded executable or shared library expose their defined exported dynamic symbols as a lookup scope (a hash table). Lookup scopes form a list. When resolving an undefined symbol ld.so walks the lookup scopes and finds the first one that defines the symbol and resolve the symbol reference. If ld.so reaches the end of lookup scopes it reports the symbol as unresolved.

There is no correspondence between the unresolved symbol name and an executable/shared library it is supposed to come from. ld.so loads all shared libraries from DT_NEEDED sections recursively, builds that list of lookup scopes and then looks for unresolved symbols in there.

How To Write Shared Libraries by U. Drepper explains this in full detail.

Maxim Egorushkin
  • 131,725
  • 17
  • 180
  • 271
  • The recursive process you've described doesn't seem correct IMHO - the library may have no DT_NEEDED structures, but still have any number of unresolved symbols. That is why I'm asking this question and want more details about what what libraries ldd finds, and how does it find them. If you are sure about your answer please correct me. – Alexey Jan 08 '19 at 11:14
  • @Alexey You didn't ask how it resolves symbols. You keep asking these linker, unresolved symbol questions. By now you should have read https://www.akkadia.org/drepper/dsohowto.pdf, it answers all your questions in full detail. – Maxim Egorushkin Jan 08 '19 at 11:17
  • Well, I wrote "I'd like to know what exactly ldd does." Nevertheless the main question is whether or not libraries reported by ldd resolve all the undefined symbols. – Alexey Jan 08 '19 at 11:22
  • @Alexey The short answer is "sometimes". Read that paper. – Maxim Egorushkin Jan 08 '19 at 11:23
  • Yes, I have to read that document. But maybe you now can correct your answer to briefly explain why "no" and then I accept it. Thank you anyway! – Alexey Jan 08 '19 at 11:26
  • No. I just suppose that ldd should print the list of libraries that is enough to resolve all the undefined referencies (i.e. the list of all libraries the input library depends on). If the list is not complete then I don't understand what is the use of this list. – Alexey Jan 08 '19 at 11:35
3

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.

n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
  • Let's suppose that ./test is a shared library. Can we still see that it has no third party dependencies then? – Alexey Jan 08 '19 at 14:53
  • @Alexey It has unresolved symbols but no dependencies, since any library or executable can provide symbols to resolve against. – n. m. could be an AI Jan 08 '19 at 15:01
  • Dependency means there is an undefined reference. If there is an undefined reference then there is a dependency. Is it right? – Alexey Jan 08 '19 at 15:41
  • @Alexey Neither assertion is correct. A dependency is a shared object name. An unresolved reference is a symbol name. They are completely different things and either can exist without the other. – n. m. could be an AI Jan 08 '19 at 17:00
2

Do libraries reported by ldd resolve all undefined references of an input library?

No. A shared library may be linked containing undefined references (and this is commonplace). So it may be linked containing undefined references that will not be resolved by any of its (recursive) DSO dependencies, or indeed any DSO or object file that exists.

foo.c

#include <stdio.h>

extern void bar(void);

void foo(void)
{
    puts(__func__);
    bar();
}

Make shared library:

$ gcc -shared -o libfoo.so foo.c

ldd libfoo.so lists recursively the DSO dependencies of libfoo.so:

$ ldd libfoo.so
    linux-vdso.so.1 (0x00007ffc30bf5000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fd19209b000)
    /lib64/ld-linux-x86-64.so.2 (0x00007fd19268e000)

None of them resolves the undefined reference to bar.

Mike Kinghan
  • 55,740
  • 12
  • 153
  • 182
  • Now let's suppose we want to create an application that uses function foo from main.c: gcc main.c -lfoo -llibc -o main.exe. We will get an unresolved reference to function bar inside the source foo.c of libfoo.so, right? We have added all the libraries reported by ldd libfoo.so, but we still have unresolved reference inside libfoo.so. So my question is what is the use of ldd and its output? – Alexey Jan 08 '19 at 12:40
  • @Alexey The purpose of ldd is to show you the name of each shared library in the recursive linkage of a shared library or dynamically linked program and of the actual file, if any, to which the runtime loader maps that name. It may be you want ask a different question: *Why would I ever want to know the dynamic dependencies of a shared library or program, as reported by `ldd`?* – Mike Kinghan Jan 08 '19 at 14:05
  • My confusion is because of the fact that ldd seems have nothing (or a little) to do with undefined references. What programming tasks require ldd? – Alexey Jan 08 '19 at 14:15
  • @Alexey That really is a different question, which I and no doubt others could answer, if you post it. It's one question at a time on SO. – Mike Kinghan Jan 08 '19 at 14:27
  • Here it is https://stackoverflow.com/questions/54092584/what-is-the-purpose-of-ldd But not everybody agree that it should be a different post because I've asked "what is the use of ldd at all" here. – Alexey Jan 08 '19 at 14:30
  • @Alexey On reading n.m's answer, I think he covers the usefulness of ldd – Mike Kinghan Jan 08 '19 at 14:50
  • I hope. Could you please tell me does it make sense to use ldd with a shared library ldd shared_library.so (instead of using ldd with an application ldd application)? – Alexey Jan 08 '19 at 14:56
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/186368/discussion-between-mike-kinghan-and-alexey). – Mike Kinghan Jan 08 '19 at 15:58
  • OK , I'm there! – Alexey Jan 08 '19 at 16:16