A while back, while working on a project that was emulating a filesystem layer
in userspace, I found out (the hard way) that the glibc implementation of the
dynamic loader, ld.so
, uses inodes to uniquely identify libraries. That is to
say, when asked to load a shared library, it checks the inode of the file
first to see if it's already been loaded.
I, of course, had stubbed out the inode-fetching portion of the filesystem API
-- making it return inode 1 for everything -- and so could not figure out why
ld.so
was failing to load the second dynamically-loaded library that a
program requested.
I feel rather slow, but it was not until today -- working on a totally
different project that nonetheless still deals with the inner workings of
ld.so
, about a year later -- that I realized a simple truth: this is how
ld.so
handles symlinked libraries. That is to say, if you have a library
libfoo.so.5
that is a symlink to libfoo.so.5.1
, and you have the following
scenario:
-
A dynamically-linked executable,
hello
, requireslibfoo.so.5
, andlibbar.so.2
, -
libbar.so.2
requireslibfoo.so.5.2
,
Then ld.so
can resolve the same-ness of libfoo.so.5
and libfoo.so.5.2
immediately without any fuss at all, simply by checking the inode -- after all,
if you follow the symlinks, you'll get the same inode.
Quite clever, I think, and I'm annoyed at myself for missing this the first time.
- ethereal