This is the mail archive of the libc-hacker@cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Re: libc/936: glibc2 - ld.so fails to load a program defining


> Zack Weinberg <zack@rabi.columbia.edu> writes:
> 
> > Just got this from the guy with the strcmp() problem, it' a new and
> > much less invasive patch.  I don't know the dynamic linker well enough
> > to evaluate it.  Comments?
> 
> The patch is bogus.  The question is: why do we re-relocate the
> dynamic linker again if it is referenced?  Roland, do you remember why
> you added this?  It is certainly no requirement.  We could simply
> remove the lines
> 
>     if (_dl_rtld_map.l_opencount > 0)
>       {
> 	/* There was an explicit ref to the dynamic linker as a shared lib.
> 	   Re-relocate ourselves with user-controlled symbol definitions.  */
> 	HP_TIMING_NOW (start);
> 	_dl_relocate_object (&_dl_rtld_map, _dl_loaded->l_scope, 0, 0);
> 	HP_TIMING_NOW (stop);
> 	HP_TIMING_DIFF (add, start, stop);
> 	HP_TIMING_ACCUM_NT (relocate_time, add);
>       }
> 
> without consequences.

No!  That would certainly have consequences, especially for the Hurd.  This
code is most certainly a requirement, and not just because the Hurd needs
it, but because this is the right semantics.  I hope you will read my long
explanation below and find it clear, and agree that there are some
important issues here not to be tweaked lightly, in semantics as well as
the pragmatics that affect the Hurd's implementation.

I thought this was explained in comments, but the dynamic linker has
changed far too much since I wrote it for me to tell any more.

In the bootstrap relocation of the dynamic linker, it uses a special symbol
resolution algorithm that always uses the dynamic linker's own definitions
for all its global symbols.  This is of course necessary for bootstrapping,
since the dynamic linker has to be whole and working before any other
modules will be loaded that might provide definitions.

So, the dynamic linker defines symbols it needs for basic operation such as
open, mmap, etc.  On Linux, these definitions all come from libc_pic.a and
so are identical to the definitions that will appear in libc.so.  But on
the Hurd, many of these functions are much more complex than a simple
system call stub, so dl-sysdep.c defines special simpler versions of them
that will work *only* in the dynamic linker at startup time, and *cannot*
be used later; it defines these as weak symbols.

After all the program's needed libraries have been loaded and relocated,
the dynamic linker is no longer in this special situation where it had to
use its own definitions of symbols such as open and mmap.  If neither the
program nor any library made reference to ld.so's own symbols, then most of
the dynamic linker will not be used any more; it only needs to stay around
to do on-demand relocations for lazy binding, and to make available the
`r_map' list for the debugger.  If it were worth the trouble, the dynamic
linker could unmap most of its own code at this point (or all of it, if
there is no lazy binding remaining to be done).  (One rarely sees this case
any more, since because of nsswitch libc.so refers to ld.so's symbols, and
one rarely dynamically links a program without libc.)

If there are references to ld.so's own symbols, such as from dlopen, then
the dynamic linker is now taking on the role of an ordinary shared library
that will be called by the program later through an ordinary explicit
function entry point.  So, its symbols are now bound as for any shared
library, and in the usual course of things its references to open, mmap,
etc. bind to the libc.so definitions.

In the common case on Linux, this results in redirecting PLT entries for
symbols like open from ld.so's copy of the code to the identical code at a
different address, in libc.so.  Since the code is completely identical,
having come originally from the same object file in libc_pic.a, this makes
no meaningful difference.  It's probably the tiniest bit nicer to your
cache, and conceivably your VM, that calls to open from ld.so and from the
rest of the program now use the same address and the same cache line of the
instructions in `open' rather than filling two cache lines with identical
contents.

On the Hurd, it just plain won't work for ld.so to use its own versions of
open et al when called from dlopen and the like, when the callers are using
the code from libc.  For example, file descriptors are implemented by
entirely different data structures in the two versions, and the data
structures used by ld.so's private version are destroyed after startup is
complete, before calling the program's entry point.

But on any system, it would not be the right semantics for the dynamic
linker to use its own definitions for these symbols.  Take the example of a
program or preload that redefines open, read, write, et al to implement
some special extra functionality not provided by the normal versions; there
are several such things around, to implement open-by-URL, auditing things,
caching things, process migration things, etc., etc.  (The exact prescribed
proper way to do this sort of interposition in glibc has changed and become
more complex since I originally designed and implemented the dynamic
linker, what with symbol versioning and __s and all--but it remains
reasonable and supported to do such a thing in some fashion or other, and
people do it.)  Using such a scheme, one can reasonably expect to point a
program at some special directory name meaningful only with this special
extra functionality (e.g. a URL as the directory name), and have it find
all its files there just as it would find them in a normal directory like
/usr/local.  This is a reasonable expectation of what to do generically
with any program, and reasonably generic programs use dlopen.  Just as
redefining open in this way makes fopen use your version of open, so it
should make dlopen use your version of open as well.  It would be
unreasonable to expect anything else.


Roland


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]