I just learned about the ldd command and I wanted to share it with you. This might be useful if you’re trying to get control over a messy project by putting it in a container. A project lacking strict attention to dependencies and automation from the beginning often ends up a mess (we know this from helping a lot of customers clean up their messes). Getting a project like this running from a base Docker image requires a lot of work to figure out which dependencies need to be installed. ldd will help you find those dependencies.

I was reading Adriaan de Jonge’s excellent post about creating the smallest possible container to run a Go program.

In order to create this image, Adriaan needs to produce a Go binary with no dynamic dependencies. He shows his first attempt does not work with the ldd command:

$ ldd $GOPATH/bin/helloworld
    linux-vdso.so.1 => (0x00007fff039fe000)
    libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f61df30f000)
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f61def84000)
    /lib64/ld-linux-x86-64.so.2 (0x00007f61df530000)

So what do we have here? The first line of output says something about linux-vdso.so.1. New to you? Me too. An educated guess should get you pretty close. The vDSO is the Linux system library the kernel provides to applications. After the name of the library, we see a hex number. This is the address to which the library will be loaded when the program is run (modulo any relocations; more later). Interesting…

On the second line, we see libpthread.so.0. You guessed it - this is the POSIX threading library. We see it points to a file and an address. The file, of course, is the location of the library binary.

The third line is the same as the second but points at the libc library.

The last line is another interesting one: ld-linux-x86-64.so.2. I will leave it to the ld-linux man page:

> > The programs ld.so and ld-linux.so* find and load the shared libraries needed by a program, prepare the program to run, and then run it. > >

So, the ld and ld-linux programs are akin to a boot and dependency injection process.

Speaking of man pages, what are the other options to ldd?

> > --version Print the version number of ldd. -v --verbose Print all information, including, for example, symbol versioning information. -u --unused Print unused direct dependencies. (Since glibc 2.3.4.) -d --data-relocs Perform relocations and report any missing objects (ELF only). -r --function-relocs Perform relocations for both data objects and functions, and report any missing objects or functions (ELF only). --help Usage information. > >

Finding unused and missing dependencies sure sounds useful when your system breaks down. I’m thankful I’ve never had to use this - these are some pretty low level concerns. More likely though I have had to use ldd but didn’t know it.

What are relocations the man page mentions? I hinted above that the hex address printed may be subject to change. Eli Bendersky has a great post about about the load-time relocation of shared libraries. The short story is a dynamic library can’t always know where its data will be located. Fixing this is part of the responsibility of the ld and ld-linux programs when they boot your program. Eli talks about how this happens in detail and talks about the modern solution that avoids the problem.

Finally, here’s how you might apply ldd to when getting control over a messy application: finding all the binary dependencies of your Ruby application. You can substitute this for your language of choice.

$ find   ~/.rvm/gems/ruby-1.9.3-p448/ -type f -name "*.so" | xargs -n 1 -P 1 -I x bash -c "echo x; ldd x"

/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/gems/gem-wrappers-1.2.7/ext/wrapper_generator/wrapper_generator.so
        not a dynamic executable
/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/gems/nokogiri-1.6.6.2/ext/nokogiri/nokogiri.so
        linux-vdso.so.1 =>  (0x00007fff5bfb7000)
        libruby.so.1.9 => /home/ubuntu/.rvm/rubies/ruby-1.9.3-p448/lib/libruby.so.1.9 (0x00007f4d145bb000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f4d14290000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f4d14079000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f4d13e5b000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f4d13c52000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f4d1388d000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f4d13689000)
        libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f4d1344f000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f4d14e33000)
/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/gems/nokogiri-1.6.6.2/lib/nokogiri/nokogiri.so
        linux-vdso.so.1 =>  (0x00007fffff8d7000)
        libruby.so.1.9 => /home/ubuntu/.rvm/rubies/ruby-1.9.3-p448/lib/libruby.so.1.9 (0x00007f3673728000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f36733fd000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007f36731e6000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f3672fc8000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f3672dbf000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f36729fa000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f36727f6000)
        libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007f36725bc000)
        /lib64/ld-linux-x86-64.so.2 (0x00007f3673fa0000)
/home/ubuntu/.rvm/gems/ruby-1.9.3-p448/extensions/x86_64-linux/1.9.1/nokogiri-1.6.6.2/nokogiri/nokogiri.so
        linux-vdso.so.1 =>  (0x00007fffc67fe000)
        libruby.so.1.9 => /home/ubuntu/.rvm/rubies/ruby-1.9.3-p448/lib/libruby.so.1.9 (0x00007fbfba936000)
        libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fbfba60b000)
        libz.so.1 => /lib/x86_64-linux-gnu/libz.so.1 (0x00007fbfba3f4000)
        libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fbfba1d6000)
        librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fbfb9fcd000)
        libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fbfb9c08000)
        libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fbfb9a04000)
        libcrypt.so.1 => /lib/x86_64-linux-gnu/libcrypt.so.1 (0x00007fbfb97ca000)
        /lib64/ld-linux-x86-64.so.2 (0x00007fbfbb1ae000)

That’s all for today! I hope you learned something!