Providing an Alternative to dlopen
()
dlopen
(3C) and
dlsym
(3C) are often used to load and exercise additional objects. See Runtime Linking Programming Interface. For example, the
following code from libdep.so.1
loads
libbar.so.1
, and on success calls
interfaces provided by libbar.so.1
.
void dep() { void *handle; if ((handle = dlopen("libbar.so.1", RTLD_LAZY)) != NULL) { int (*fptr)(); if ((fptr = (int (*)())dlsym(handle, "bar1")) != NULL) (*fptr)(arg1); if ((fptr = (int (*)())dlsym(handle, "bar2")) != NULL) (*fptr)(arg2); .... } }
Although very flexible, this model of using
dlopen
() and dlsym
()
is an unnatural coding style, and has some drawbacks.
-
The object in which the symbols are expected to exist must be known.
-
The calls through function pointers provide no means of verification by either the compiler, or
lint
(1).
This code can be simplified if the object that supplies the required interfaces satisfies the following conditions.
-
The object can be established as a dependency at link-edit time.
-
The object is always available.
By exploiting that a function reference can trigger lazy loading, the
same delayed loading of libbar.so.1
can be
achieved. In this case, the reference to the function
bar1
() results in lazy loading the
associated dependency. This coding is far more natural, and the use
of standard function calls provides for compiler, or
lint
(1) validation.
void dep()
{
bar1(arg1);
bar2(arg2);
....
}
$ cc -G -o libdep.so.1 dep.c -L. -z lazyload -lbar -lc
However, this model fails if the object that provides the required
interfaces is not always available. Should the application be
exercised when LD_BIND_NOW
is set, or the shared
object be loaded through
dlopen
(3C) with the RTLD_NOW
flag, then all references from the associated objects are processed.
Any failure to bind a symbol reference to a definition results in a
fatal error.
In this case, it is desirable to test for the existence of the dependency, without having to know the dependency name. A means of testing for the availability of a dependency that satisfies a function reference is required.
A robust model for testing for the existence of a
function can be achieved with deferred symbol
references, or deferred dependencies, and use
of
dlsym
(3C) with the
RTLD_PROBE
handle.
Deferred symbol references differ from standard symbol references in the following details.
-
Deferred references can only be established for function calls.
-
Deferred references are directly bound at runtime to the associated dependency.
-
Deferred references are not resolved as part of standard relocation processing, or
LD_BIND_NOW
processing, or throughdlopen
(3C) with theRTLD_NOW
flag.
Deferred references are resolved during process execution, when the associated function is first referenced. The assurance of this delayed resolution provides a window where the caller can test for the existence of the deferred dependency before making calls to the deferred function.