Libraries and Linking

NOTE: Do not confuse linking with loading!

Static Library (.a) - Statically Linked Library

A Library that is linked statically in an executable, i.e. the executable self contains all the library symbols it needs to run.

Shared Library (.so) - Dynamically Linked Library

Aka DSO - "Dynamic Shared Object(s)". A library that is shared among different applications, i.e. it is loaded in memory only one time for all the applications linked to it.

It is loaded by the kernel.

Dynamic Linker

Used to load shared libraries. Aka ld.so or ld-linux.so, somewhere in /lib/ld-linux.so.*. You can invoke the linker as an executable, followed by an ELF file.

List all shared libraries and how they are resolved:

$ /lib64/ld-linux-x86-64.so.2 --list <path to executable>

Relevant variables:

  • LD_PRELOAD: unconditionally preload the specified shared library, even if the program does not require it. This is done before actually loading the libraries the program requested.

  • LD_LIBRARY_PATH: the path to look at when loading libraries, before looking into system paths.

  • LD_DEBUG: LD_DEBUG=all <executable-name> to show ld debug info while running an executable.

Dynamically Loaded (DL) Library

Library that is loaded at runtime using dlopen(...). This is useful when you want to load at runtime some code in a library, like a plugin.

PLT and GOT

PLT: Procedure Linkage Table. Stub of code that looks up for a shared library addresses for functions in a table, called GOT: Global Offset Table.

NOTE: addresses are actually stored / looked up in the .got.plt table!

Example

Your code in main() is calling getpid(). The disassemble is:

0x0804845d <+25>:   call   0x8048350 <getpid@plt>

getpid() is a libc function, so the call is done going thru the PLT stub

PLT:

   0x08048350 <+0>:    jmp    *0x804a004
   0x08048356 <+6>:    push   $0x8
   0x0804835b <+11>:   jmp    0x8048330

The PLT is first trying to jump in the GOT entry for the function.

  • If it's the first time getpid() is called, the GOT entry will just contain as address the instruction right after the jump. So the dynamic linker will do the lookup of the getpid name into the shared library, and store its address in the GOT entry.

  • On subsequent calls to getpid, the GOT entry will contain the getpid address inside libc, so there will be no lookup :-)

More Info

LD Flags

Start and end group

Used for tstatic libraries / archives only. Wrap archives with --start-group, --end-group to allow specifying archives in any order; references resolution done also for circular references.

As needed / Not as needed

--no-as-needed is the default linking mode for shared libraries => the library is always added as dependency (as shown by ldd), even if not used at all.

--as-needed overrides default linking mode only include library as dependency if it is actually needed / contains symbols needed by other objects.

Assuming you have the statically version of the lib installed (typically distributed in a -dbg package), this tells ld to switch to statically libfoo:

-Wl,-Bstatic -lfoo -Wl,-Bdynamic

pkg-config

Given a library package name installed on the system, retrieve metadata about that library. E.g.:

  • it can be used to retrieve library compile and link flags.
$ pkg-config --cflags --libs uuid # uuid is the name of the library / name of the package containing the library
-I/usr/include/uuid -luuid

List all libraries packages name:

$ pkg-config --list-all

ldconfig

Used to update the runtime linker cache (to speed up library lookup), and to handle the links from ".so" to the actual libraries path. It can also be used to retrieve the path of libraries on the system (--print-cache).

ldd

Equivalent of LD_DEBUG=libs <executable>.

vDSO (Virtual dynamic shared object)

Shared library that the kernel automatically loads into the process memory space. It is used to map a subset of frequently used syscall, to avoid all of the overhead of context switching:

  • Only a very limited set of syscall is mapped (gettimeofday, time, ...)
  • You can actually see the lib with ldd binary-name (linux-vdso.so.1)
  • Library is built when you build the kernel. You can load symbols from it, as any other lib