Deferred Symbol References

Deferred symbol references are established from mapfile definitions. The following mapfile identifies a family of bar() functions as deferred references that should be resolved to libbar.so.1.

$ cat mapfile
$mapfile_version 2

SYMBOL_SCOPE {
        global:
                bar1 { DEFERRED = libbar.so.1 };
                bar2 { DEFERRED = libbar.so.1 };
                ....
};

The deferred nature of these references can be observed from the symbol information and dynamic information defined within the referring object.

$ cc -G -o libdef.so.1 def.c -Kpic -M mapfile -lc
$ elfdump -y libdef.so.1 | fgrep DEFERRED
    [9]  [ DEPEND DEFERRED ]    [2] libbar.so.1   bar1
   [15]  [ DEPEND DEFERRED ]    [2] libbar.so.1   bar2
   ....
$ elfdump -d libdef.so.1 | fgrep DEFERRED
    [2]  SUNW_DEFERRED   0x176      libbar.so.1

At runtime, a dlsym(RTLD_PROBE) against one of the bar() symbols can be used to determine whether the family of symbols are available. On success, the members of the family can be called as direct function calls. These calls are much more legible and easier to write, and allow the compiler to catch errors in their calling sequences.

void dep()
{
        if (dlsym(RTLD_PROBE, "bar1")) {
                bar1(arg1);
                bar2(arg2);
                ....
        }
}

There are a couple scenarios that can be useful for this technique. The first is to test for new functionality in an existing dependency, and the other is to test whether a dependency exists.

Applications can be built so that they execute on a series of OS releases. The core functionality of the application must execute on the oldest version of the OS the application is targeted to. However, newer OS releases can provide new, or more optimal features. By establishing deferred references to these features, an application can test for the features existence before calling the associated functionality.

Deferred references can also be used to test that a dependency exists. This capability is essentially equivalent to establishing a deferred dependency with the -z deferred option. See the following section Deferred Dependencies.

In both scenarios, the dlsym(RTLD_PROBE) test ensures at runtime that a dependency defining the required symbol exists. The dependency can be one that is already in use by the caller to provide other symbol definitions. Or, the dependency may be loaded explicitly to satisfy the dlsym() request. In either case, once the existence of the dependency is confirmed, the associated symbol, or others that are known to exist with the associated symbol, can be called freely.