Testing for Functionality

The special handles RTLD_DEFAULT and RTLD_PROBE enable an application to test for the existence of a symbol.

The RTLD_DEFAULT handle employs the same default search rules used by the runtime linker to resolve any symbol reference from the calling object. See Default Symbol Lookup Model. Two aspects of this model should be noted.

  • In the absence of direct binding, a symbol reference from a shared object that matches a symbol reference from a dynamic executable is bound to the procedure linkage table entry associated with the reference from the executable. See Procedure Linkage Table (Processor-Specific). This artifact of dynamic linking enables both components within the process see a single address for a function.

  • If a symbol definition can not be found to satisfy a non-weak symbol reference within the objects that are currently loaded in the process, a lazy loading fallback is initiated. This fallback iterates through each loaded dynamic object, and loads any pending lazy loadable, non-deferred, objects in an attempt to resolve the symbol. This model compensates for objects that have not fully defined their dependencies. However, this compensation can undermine the advantages of lazy loading. Unnecessary objects can be loaded, or an exhaustive loading of all lazy loadable objects can occur should the relocation symbol not be found.

RTLD_PROBE follows a similar model to RTLD_DEFAULT, but differs in the two aspects noted with RTLD_DEFAULT.

  • RTLD_PROBE only binds to explicit symbol definitions, and is not bound to any procedure linkage table entry within the executable.

  • RTLD_PROBE does not initiate an exhaustive lazy loading fallback.

RTLD_PROBE is the most appropriate flag to use to detect the presence of a symbol within an existing process.

RTLD_DEFAULT and RTLD_PROBE can both initiate an explicit lazy load. An object can make reference to a function, and that reference can be established through a lazy loadable dependency. Prior to calling this function, RTLD_DEFAULT or RTLD_PROBE can be used to test for the existence of the function. Because the object makes reference to the function, an attempt is first made to load the associated lazy dependency. The rules for RTLD_DEFAULT and RTLD_PROBE are then followed to bind to the function. In the following example, an RTLD_PROBE call is used both to trigger a lazy load, and to bind to the loaded dependency if the dependency exists.

void foo()
{
        if (dlsym(RTLD_PROBE, "foo1")) {
                foo1(arg1);
                foo2(arg2);
                ....
}

To provide a robust and flexible model for testing for functionally, the associated lazy dependencies should be explicitly tagged as deferred. See Providing an Alternative to dlopen. This tagging also provides a means of changing the deferred dependency at runtime.

The use of RTLD_DEFAULT or RTLD_PROBE provide a more robust alternative to the use of undefined weak references, as discussed in Weak Symbols.