|
Description
|
The runtime linker employs a fall-back symbol search mechanism for use with objects
that employ lazy loading. Without this mechanism many objects that don't express
their required dependencies would fail in a lazy loadable environment.
Should the search for a symbol fail, ld.so.1 looks to see if any lazy loadable
dependencies are still pending, and if so starts loading the lazy dependencies in
a final attempt to located the required symbol.
Although this mechanism works well to glue together badly built dependencies, there
is some unnecessary overhead in the case that a lazy loadable dependency fails to
load. The scenario is something like this:
. The search for a symbol triggers a lazy load.
. The lazy loadable object doesn't exist, or worse yet, one of the many
dependencies of the lazy loaded object doesn't exist, or a symbol required
to relocate one of the lazy load family can't be found.
. The runtime linker cleans up the lazy loaded family.
. A search of any presently loaded objects doesn't provide the required
symbol.
. The runtime linker starts picking off presently unloaded lazy loadable
dependencies.
. One of these dependencies turns out to be the lazy load dependency that
we've already failed to load - we repeat the failure.
It would be very easy to tag any lazy load failure, and thus skip this "pending"
dependency on any future processing. This in fact was the case prior to the
integration of 6215444. However, besides some of the interesting scenarios we
can come up with, there's been a goal of remaining very dynamic in regards to
lazy loading failures. With todays long running processes, and the plethora of
plugin capabilities, it's possible that a lazy load (or dlopen) could fail, but the
user can correct the situation by installing the required package components. In
this case it would nice to re-exercise the lazy load and have it succeed, without
having to restart the process.
What we have today is very flexible, but there can be considerable cost when a
lazy load fails. A compromise would treat each entry into ld.so.1 as a single
operation, and only allow a lazy load failure to be triggered once within this
operation. Should the runtime linker be called again, then the lazy load could
be reexamined.
This model isn't a panacea. A user could dlsym() for dozens of unresolvable
symbols, and each dlsym() would trigger an attempt to load a lazy failure.
But typically it seems that lazy load failures are uncommon, and once a
failure has occurred, another dependency is loaded that satisfies the original
symbol requirement. This new dependency continues to satisfy new symbol searches
without the lazy fall-back needing to be triggered.
|