Linker and Libraries Guide

Binding to Additional Version Definitions

Sometimes it is desirable to record additional version dependencies than would be produced from the normal symbol binding of an object. This can be achieved using the $ADDVERS file control directive. This section describes a couple of scenarios where this additional binding might be useful.

Continuing with the libfoo.so.1 example, assume that in ReleaseX+2, the version definition SUNW_1.1 is subdivided into two standard releases, STAND_A and STAND_B. To preserve compatibility, the SUNW_1.1 version definition must be maintained, but now it is expressed as inheriting the two standard definitions:


$ pvs -dsv libfoo.so.1
        libfoo.so.1:
                _end;
                _GLOBAL_OFFSET_TABLE_;
                _DYNAMIC;
                _edata;
                _PROCEDURE_LINKAGE_TABLE_;
                _etext;
        SUNW_1.1:           {STAND_A, STAND_B}:
                SUNW_1.1;
        SUNW_1.2:           {SUNW_1.1}:
                bar;
        STAND_A:
                foo1;
                STAND_A;
        STAND_B:
                foo2;
                STAND_B;

If we continued to create our application prog so that its only requirement is the interface symbol foo1, it will have a single dependency on the version definition STAND_A. This precludes running prog on a system where libfoo.so.1 is less than ReleaseX+2 as the version definition STAND_A did not exist in previous releases, even though the interface foo1 did.

Therefore, the application prog can be built to align its requirement with previous releases by creating a dependency on SUNW_1.1 by using the following file control directive:


$ cat mapfile
libfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.1;
$ cat prog
extern void foo1();

main()
{
        foo1();
}
$ cc -M mapfile -o prog prog.c -L. -R. -lfoo
$ pvs -r prog
        libfoo.so.1 (SUNW_1.1);

This explicit dependency is sufficient to encapsulate the true dependency requirements and satisfy compatibility with older releases.

In "Creating a Weak Version Definition" it was described how weak version definitions can be used to mark an internal implementation change. These version definitions are well suited to indicate bug fixes and performance improvements made to an object. If the existence of a weak version is required for the correct execution of an application, then an explicit dependency on this version definition can be generated.

Establishing such a dependency can be important when a bug fix, or performance improvement, is critical for the application to function correctly.

Continuing with the libfoo.so.1 example, assume a bug fix is incorporated as the weak version definition SUNW_1.2.1 in software ReleaseX+3:


$ pvs -dsv libfoo.so.1
        libfoo.so.1:
                _end;
                _GLOBAL_OFFSET_TABLE_;
                _DYNAMIC;
                _edata;
                _PROCEDURE_LINKAGE_TABLE_;
                _etext;
        SUNW_1.1:           {STAND_A, STAND_B}:
                SUNW_1.1;
        SUNW_1.2:           {SUNW_1.1}:
                bar;
        STAND_A:
                foo1;
                STAND_A;
        STAND_B:
                foo2;
                STAND_B;
        SUNW_1.2.1 [WEAK]:  {SUNW_1.2}:
                SUNW_1.2.1;

Normally, if an application is built against this shared object, it will record a weak dependency on the version definition SUNW_1.2.1. This dependency is informational only, in that it will not cause termination of the application should the version definition not be found in the libfoo.so.1 used at runtime.

The file control directive $ADDVERS can be used to generate an explicit dependency on a version definition. If this definition is weak, then this explicit reference also causes the version definition to be promoted to a strong dependency.

Therefore, the application prog can be built to enforce the requirement that the SUNW_1.2.1 interface be available at runtime by using the following file control directive:


$ cat mapfile
libfoo.so - SUNW_1.1 $ADDVERS=SUNW_1.2.1;
$ cat prog
extern void foo1();

main()
{
        foo1();
}
$ cc -M mapfile -o prog prog.c -L. -R. -lfoo
$ pvs -r prog
        libfoo.so.1 (SUNW_1.2.1);

Here, prog has been built with an explicit dependency on the interface STAND_A. Because the version definition SUNW_1.2.1 is promoted to a strong version, it is also normalized with the dependency STAND_A. At runtime, if the version definition SUNW_1.2.1 cannot be found, a fatal error will be generated.


Note -

When working with one or two dependencies, explicit binding to a version definition can also be achieved by referencing the version definition symbol. This is most easily achieved by using the link-editor's -u option. However, a symbol reference is nonselective, and when working with multiple dependencies, which might contain similarly named version definitions, this technique is insufficient to create explicit bindings.