When creating a dynamic object against a shared object containing version definitions, you can instruct the link-editor to limit the binding to specific version definitions. Effectively, the link-editor enables you to control an object's binding to specific interfaces.
An object's binding requirements can be controlled using a file control directive. This directive is supplied using the link-editor's -M option and an associated mapfile. The syntax for these file control mapfile directives is:
name - version [ version ... ] [ $ADDVERS=version ]; |
name – Represents the name of the shared object dependency. This name should match the shared object's compilation environment name as used by the link-editor. See Library Naming Conventions.
version – Represents the version definition name within the shared object that should be made available for binding. Multiple version definitions can be specified.
$ADDVERS – Allows for additional version definitions to be recorded.
This binding control can be useful:
If a shared object has been versioned to define unique and independent versions, possibly defining different standards interfaces. The application can then ensure that its bindings meet the requirements of a specific interface.
If a shared object has been versioned over several software releases, application developers can restrict themselves to the interfaces that were available in a previous software release. Thus, an application can be built using the latest release of the shared object in the knowledge that the application's interface requirements can be met by a previous release of the shared object.
The following example illustrates the user of the version control mechanism. This example uses the shared object libfoo.so.1 containing the following version interface definitions:
$ pvs -dsv libfoo.so.1 libfoo.so.1: _end; _GLOBAL_OFFSET_TABLE_; _DYNAMIC; _edata; _PROCEDURE_LINKAGE_TABLE_; _etext; SUNW_1.1: foo1; foo2; SUNW_1.1; SUNW_1.2: {SUNW_1.1}: bar; |
The version definitions SUNW_1.1 and SUNW_1.2 represent interfaces within libfoo.so.1 that were made available in software Release X and Release X+1 respectively.
An application can be built to bind only to the interfaces available in Release X by using the following version control mapfile directive:
$ cat mapfile libfoo.so - SUNW_1.1; |
For example, suppose you develop an application, prog, and want to ensure that the application can run on Release X. The application can then only use the interfaces available in that release. If the application mistakenly references the symbol bar, then the application's noncompliance to the required interface will be signalled by the link-editor as an undefined symbol error:
$ cat prog.c extern void foo1(); extern void bar(); main() { foo1(); bar(); } $ cc -o prog prog.c -M mapfile -L. -R. -lfoo Undefined first referenced symbol in file bar prog.o (symbol belongs to unavailable \ version ./libfoo.so (SUNW_1.2)) ld: fatal: Symbol referencing errors. No output written to prog |
To be compliant with the SUNW_1.1 interface, you must remove the reference to bar. You can either rework the application to remove the requirement on bar, or add an implementation of bar to the creation of the application.
To record more version dependencies than would be produced from the normal symbol binding of an object, use 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 Release X+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. In this example, this version definition 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 the only requirement of application prog is the interface symbol foo1, the application 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 Release X+2. The version definition STAND_A did not exist in previous releases, even though the interface foo1 did.
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.
Creating a Weak Version Definition 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 Release X+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, the application records a weak dependency on the version definition SUNW_1.2.1. This dependency is informational only. This dependency does not cause termination of the application should the version definition not exist 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.
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); |
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 is generated.
When working with one or two dependencies, you can use the link-editor's -u option to explicitly bind to a version definition by referencing the version definition symbol. However, a symbol reference is nonselective. When working with multiple dependencies, that might contain similarly named version definitions, this technique is insufficient to create explicit bindings.