Shared libraries and the dynamic linker

Shared libraries: how a dynamically linked program finds the code it needs at run time, why a freshly installed library can still be invisible, and the two ways to fix that.

Lesson 3 of 6 in objective 102. Linux installation and package management, part of LPIC-1 Exam 101-500.

Where the dynamic linker looks when a program starts, and where it stops. A search over 3 places, tried in this order: the first hit ends it, and everything under the one that hits is never looked at. Going down a step means no copy of the library there. First, LD_LIBRARY_PATH (searched before the cache; useful for testing, a poor permanent answer); a hit there means that copy runs even when the cache names another. Then, /etc/ld.so.cache (built by ldconfig from /etc/ld.so.conf, and stale until you rerun it); a hit there means that copy is loaded and nothing below is searched. Last, /lib and /usr/lib (the defaults, which need no entry in ld.so.conf); a hit there means that copy is loaded and nothing below is searched. A miss at every one of them: not found — the line ldd prints when the linker was never told where to look. LD_LIBRARY_PATH searched before the cache; useful for testing, a poor permanent answer that copy runs even when the cache names another no copy of the library there /etc/ld.so.cache built by ldconfig from /etc/ld.so.conf, and stale until you rerun it that copy is loaded and nothing below is searched /lib and /usr/lib the defaults, which need no entry in ld.so.conf that copy is loaded and nothing below is searched not found — the line ldd prints when the linker was never told where to look
Where the dynamic linker looks when a program starts, and where it stops.

Dynamic linking, and the cache that makes it fast

A statically linked program contains every library function it uses and depends on nothing at run time. A dynamically linked one — which is almost everything — contains only references, and the dynamic linker resolves them when the program starts. ldd prints that list for a binary, showing each required soname and the file it currently resolves to; a line reading "not found" is precisely the failure this objective is about.

Searching the whole filesystem on every program start would be slow, so the linker consults a cache: /etc/ld.so.cache, a binary file built by ldconfig from the directories listed in /etc/ld.so.conf and the files included from /etc/ld.so.conf.d/. This is why installing a library into a new directory is not enough — until you add the directory and run ldconfig, the linker does not know to look there.

LD_LIBRARY_PATH is the override: directories in it are searched before the cache. It is useful for testing and for running a program against a library you have not installed system-wide, and it is a poor permanent answer, because it applies to whatever inherits the environment rather than to the one program that needed it.

Sonames, and why versions do not break everything

A library file is usually named something like libfoo.so.1.2.3, with a symlink libfoo.so.1 pointing at it — that shorter name is the soname, and it is what a program records. The scheme means a compatible bug-fix release can replace the file and every program keeps working, while an incompatible release gets a new soname and the two can sit side by side. ldconfig is also what creates those symlinks, which is the second reason running it matters.

That makes three names for one library, and a question will lay all three out and ask which one the program holds. The readline history library ships as the file /usr/lib/x86_64-linux-gnu/libhistory.so.8.1; libhistory.so.8 is the soname symlink beside it, carrying the interface version and nothing finer; and libhistory.so, the unversioned linker name, is shipped only in the development package and is what the compiler follows at build time. The full file name is too specific to record and the unversioned one too vague, so the soname is the one written into the binary — which is why an update to .8.2 needs no rebuild and a move to .so.9 installs alongside rather than over the top.

The two commands sit on opposite sides of the bin/sbin split, and a question will use the full path rather than the name to test whether you know which. ldd only reports, so anyone may run it and it is /usr/bin/ldd. ldconfig writes the system-wide cache, so it is an administrative tool at /usr/sbin/ldconfig, reached as /sbin/ldconfig on distributions that have not merged the two. Being unable to run ldconfig as an ordinary user is the rule working, not a broken install.

Two hops sit between the soname a program records and the file that is opened. Left column, The name doing the pointing; right column, What that name turns out to be. The soname a program records and The entry ldconfig put in the cache both point at libfoo.so.1, a symbolic link (ldconfig also creates these symlinks — the second reason running it matters), which in turn reaches libfoo.so.1.2.3, the file (A compatible bug fix replaces this file and every program keeps working). The name doing the pointing What that name turns out to be The soname a program records The entry ldconfig put in the cache libfoo.so.1, a symbolic link ldconfig also creates these symlinks — the second reason running it matters libfoo.so.1.2.3, the file A compatible bug fix replaces this file and every program keeps working
Two hops sit between the soname a program records and the file that is opened.
/usr/bin/ldd /usr/local/bin/reportlibvendor.so.1 => not foundlibc.so.6 => /lib/x86_64-linux-gnu/libc.so.6the file exists in /opt/vendor/lib — the linker has not been toldecho /opt/vendor/lib > /etc/ld.so.conf.d/vendor.conf/usr/sbin/ldconfigldconfig -p | grep libvendorlibvendor.so.1 (libc6,x86-64) => /opt/vendor/lib/libvendor.so.1
A library that is installed and still invisible, and the fix.

Worth carrying in

/usr/bin/ldd
The shared libraries a program needs, and what each resolves to now. A reporting tool, so not in sbin.
/usr/sbin/ldconfig
Rebuild /etc/ld.so.cache and the soname symlinks. -p prints the current cache.
/etc/ld.so.conf
Directories the cache is built from, plus whatever ld.so.conf.d includes.
/etc/ld.so.cache
The binary cache the dynamic linker actually reads.
LD_LIBRARY_PATH
Colon-separated directories searched before the cache. For testing, not for production.
soname
The versioned name a program records — libfoo.so.1, not the full file name.

What the exam does with this

Objective
102. Linux installation and package management
Share of the exam
18.33% (the whole objective)
Questions in this lesson
6
Signed for by a person
0

Partly checked. None of the 6 questions here has been read against the cited source by a person. 6 questions have been checked against their cited clause by an automated pass — which is not the same thing, and is not a signature.

Only questions a person has signed for are used in mock exams here. That is the whole difference between the two kinds of checking above.

How these questions are written — where each question comes from, what the verification ledger records, and what happens when one is found wrong.

Drill this lesson

A lesson is one sitting: the trainer draws a short run from these questions alone and spaces the ones you get wrong.

Practise Shared libraries and the dynamic linker

Questions in this lesson

Practise Shared libraries and the dynamic linker

The rest of objective 102