Creating a Version Definition
Version definitions commonly consist of an association
of symbol names to a unique version name. These associations are
established within a mapfile
and supplied to
the final link-edit of an object using the link-editor's
-M
option. This technique is introduced in
the section Reducing Symbol Scope.
A version definition is established whenever a version name is
specified as part of the mapfile
directive. In
the following example, two source files are combined, together with
mapfile
directives, to produce an
object with a defined public interface.
$ cat foo.c #include <stdio.h> extern const char *_foo1; void foo1() { (void) printf(_foo1); } $ cat data.c const char *_foo1 = "string used by foo1()\n"; $ cat mapfile $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { # Release X global: foo1; local: *; }; $ cc -c -Kpic foo.c data.c $ cc -o libfoo.so.1 -M mapfile -G foo.o data.o $ elfdump -sN.symtab libfoo.so.1 | grep 'foo.$' [32] 0x1074c 0x4 OBJT LOCL H 0 .data _foo1 [53] 0x560 0x38 FUNC GLOB D 0 .text foo1
The symbol foo1
is the only global
symbol that is defined to provide the shared object's public
interface. The special auto-reduction directive "*"
causes the reduction of all other global symbols to have local
binding within the object being generated. The auto-reduction
directive is described in SYMBOL_SCOPE and SYMBOL_VERSION Directives. The associated
version name, SUNW_1.1
, causes the generation of
a version definition. Thus, the shared object's public interface
consists of the global symbol foo1
associated to
the internal version definition SUNW_1.1
.
Whenever a version definition, or the auto-reduction directive, are used to generate an object, a base version definition is also created. This base version is defined using the name of the object being built. This base version is used to associate any reserved symbols generated by the link-editor. See Generating the Output File for a list of reserved symbols.
The version definitions that are contained within an object can be displayed using
pvs
(1) with the -d
option.
$ pvs -d libfoo.so.1
libfoo.so.1;
SUNW_1.1;
The object libfoo.so.1
has an internal version
definition named SUNW_1.1
, together with a base
version definition libfoo.so.1
.
Note:
The link-editor's-z noversion
option allows
symbol reduction to be directed by a
mapfile
but suppresses the
creation of version definitions.
From this initial version definition, the object can evolve by adding
new interfaces together with updated functionality. For example, a
new function, foo2
, together with its supporting
data structures, can be added to the object by updating the source
files foo.c
and
data.c
.
$ cat foo.c #include <stdio.h> extern const char *_foo1, *_foo2; void foo1() { (void) printf(_foo1); } void foo2() { (void) printf(_foo2); } $ cat data.c const char *_foo1 = "string used by foo1()\n"; const char *_foo2 = "string used by foo2()\n";
A new version definition, SUNW_1.2
, can be created
to define a new interface representing the symbol
foo2
. In addition, this new interface can
be defined to inherit the original version definition
SUNW_1.1
.
The creation of this new interface is important, as the interface describes the evolution of the object. These interfaces enable users to verify and select the interfaces to bind with. These concepts are covered in more detail in Binding to a Version Definition and in Specifying a Version Binding.
The following example shows the mapfile
directives that create these two interfaces.
$ cat mapfile $mapfile_version 2 SYMBOL_VERSION SUNW_1.1 { # Release X global: foo1; local: *; }; SYMBOL_VERSION SUNW_1.2 { # Release X+1 global: foo2; } SUNW_1.1; $ cc -o libfoo.so.1 -M mapfile -G foo.o data.o $ elfdump -sN.symtab libfoo.so.1 | grep 'foo.$' [28] 0x107a4 0x4 OBJT LOCL H 0 .data _foo1 [29] 0x107a8 0x4 OBJT LOCL H 0 .data _foo2 [48] 0x5e8 0x20 FUNC GLOB D 0 .text foo1 [51] 0x618 0x20 FUNC GLOB D 0 .text foo2
The symbols foo1
and foo2
are
both defined to be part of the shared object's public interface.
However, each of these symbols is assigned to a different version
definition. foo1
is assigned to version
SUNW_1.1
. foo2
is
assigned to version SUNW_1.2
.
These version definitions, their inheritance, and their
symbol association can be displayed using
pvs
(1) together with the
-d
, -v
and -s
options.
$ pvs -dsv libfoo.so.1
libfoo.so.1:
_end;
_GLOBAL_OFFSET_TABLE_;
_DYNAMIC;
_edata;
_PROCEDURE_LINKAGE_TABLE_;
_etext;
SUNW_1.1:
foo1;
SUNW_1.1;
SUNW_1.2: {SUNW_1.1}:
foo2;
SUNW_1.2
The version definition SUNW_1.2
has a dependency on
the version definition SUNW_1.1
.
The inheritance of one version definition by another version definition is a useful technique. This inheritance reduces the version information that is eventually recorded by any object that binds to a version dependency. Version inheritance is covered in more detail in the section Binding to a Version Definition.
A version definition symbol is created and associated with a version
definition. As shown in the previous
pvs
(1) example, these symbols are displayed
when using the -v
option.