| United States-English |
|
|
|
![]() |
HP-UX Linker and Libraries User's Guide: HP 9000 Computers > Chapter 6 Shared Library Management
Routines Initializers for Shared Libraries |
|
A shared library can have an initialization routine—known as an initializer—that is called when the load module (a shared library or executable) is loaded (initializer) or explicitly unloaded (terminator). Typically, an initializer is used to initialize a shared library's data when the library is loaded. When a program begins execution its initializers are called before any other user code is executed.This allow for setup at initialization and cleanup at termination. Also, when a shared library is explicitly loaded using shl_load or dlopen or unloaded using shl_unload or dlclose, it initializers and terminators are called at the appropriate time. In 64-bit mode, you can specify initializers and terminators even for archive libraries or nonshared executables. The linker supports two different types of initializers and terminators:
HP-UX 10.X style initializers are the same type supported in all HP-UX 10.X releases. These are called both before the user's code is started or a shared library is loaded (using shl_load or dlopen) as well as when the shared library is unloaded (using shl_unload or dlclose). The linker option +I is used to create this type of initializer. The function returns nothing but takes two arguments. The first is a handle to the shared library being initialized. This handle can be used in calling shl_load routines. The second is set to non-zero at startup and zero at program termination.
See “32-bit Mode Initializers” for more information on using these initiators. This style uses init and fini functions to handle initialization operations. Inits are called before the user's code starts or when a shared library is loaded. They are functions which take no arguments and return nothing. The C compiler pragma "init" is used to declare them. For example:
The ld command supports the +init option to specify the initializer. Finis are called after the user's code terminates by either calling the libc exit function, returning from the main or _start functions, or when the shared library which contains the fini is unloaded from memory. Like inits, these also take no arguments and return nothing. The C compiler pragma "fini" is used to create them. For example:
The ld command supports the +fini option to specify theterminator. The 32-bit mode linker supports HP-UX 10.X style initializers. This section contains the following topics: The initializer is called for libraries that are loaded implicitly at program startup, or explicitly with shl_load. When calling initializers for implicitly loaded libraries, the dynamic loader waits until all libraries have been loaded before calling the initializers. It calls the initializers in depth-first order—that is, the initializers are called in the reverse order in which the libraries are searched for symbols. All initializers are called before the main program begins execution. When calling the initializer for explicitly loaded libraries, the dynamic loader waits until any dependent libraries are loaded before calling the initializers. As with implicitly loaded libraries, initializers are called in depth-first order. Note that initializers can be disabled for explicitly loaded libraries with the BIND_NOSTART flag to shl_load. For more information, see “The shl_load and cxxshl_load Routines ”. To declare the name of the initializer, use the +I linker option when creating the shared library. The syntax of the +I option is: +I initializer where initializer is the initializer's name. Multiple initializers may be called by repeating the +I initializer option. For example, to create a shared library named libfoo.sl that uses an initializer named init_foo, use this linker command line:
Multiple initializers are executed in the same order that they appear on the command line; they are unloaded in reverse order. (This applies only to the calling order within a shared library, not across multiple shared libraries.)
Initializers behave the same as other symbols; once they are bound they cannot be overridden with a new symbol through the use of shl_definesym() or by loading a more visible occurrence of the initializer symbol with the BIND_FIRST flag. What this means is that once the initializer is executed upon a load, it is guaranteed to be the same initializer that is called on an explicit unload.
The initializers cannot be defined as local definitions. Initializers cannot be hidden through the use of the -h option when building a shared library. It is strongly recommended that initializers be defined with names which do not cause name collisions with other user-defined names in order to avoid overriding behavior of shared library symbol binding. Prior to the HP-UX 10.0 release, initializer's addresses could be accessed through the initializer field of the shared library descriptor which is returned from a call to shl_get(). To support multiple initializers, the shl_getsymbols() routine has been enhanced to support the return of the initializer's address. If only one initializer is specified for a given library, its address is still available through the initializer field of a shared library descriptor. If more than one initializer is specified, the initializer field will be set to NO_INITIALIZER. Access to multiple initializers can then be accomplished through the use of shl_getsymbols(). (The shl_getsymbols() routine can also access a single initializer.)
To access initializers, a new flag, INITIALIZERS, has been defined for the shl_getsymbols() routine. It can be ORed with the NO_VALUES and GLOBAL_VALUES flags. For example,
If the GLOBAL_VALUES modifier is not used and the initializer is defined in another shared library or in the program file, shl_getsymbols() does not find the initializer for the requested library because it is not defined within the library. For more information on the usage of shl_getsymbols(), see “The shl_getsymbols Routine”. One way to use initializers is to define a unique initializer for each library. For instance, the following example shows the source code for a library named libfoo.sl that contains an initializer named init_foo: Example 6-1 C Source for libfoo.sl
You can use the +I linker option to register a routine as an initializer. Here are the commands to create libfoo.sl and to register init_foo as the initializer:
To use this technique with multiple libraries, each library should have a unique initializer name. The following example program loads and unloads libfoo.sl. Example 6-2 C Source for testlib
The following is the output of running the testlib program: Rather than have a unique initializer for each library, libraries could have one initializer that calls the actual initialization code for each library. To use this technique, each library declares and references the same initializer (for example, _INITIALIZER), which calls the appropriate initialization code for each library. This is easily done by defining load and unload functions in each library. When _INITIALIZER is called, it uses shl_findsym to find and call the load or unload function (depending on the value of the loading flag). The following example shows the source for an _INITIALIZER function: Example 6-4 C Source for _INITIALIZER (file init.c)
The following two source files show shared libraries that have registered _INITIALIZER. Example 6-5 C Source for libunits.sl
Example 6-6 C Source for libtwo.sl
Here are the commands used to build these libraries:
The following is an example program that loads these two libraries: Example 6-7 C Source for testlib2
Here is the compiler command used to create the executable testlib2:
Note that the -Wl,-E option is required to cause the linker to export all symbols from the main program. This allows the shared libraries to find the _INITIALIZER function in the main executable. Finally, the output from running testlib2 is shown: Output of testlib2
The 64-bit mode linker support both styles of initializers:
This example consists of three shared libraries lib1.sl, lib2.sl and lib3.sl. The lib1.sl depends on lib3.sl. The main program (a.out) depends on lib1.sl and lib2.sl. Each shared library has an init style initializer and a fini style terminator. The lib1.sl and lib2.sl uses linker options (+init and +fini) to specify the initializers and terminators and lib3.sl uses compiler pragmas. Example 6-8 C source for lib1.sl (file lib1.c):
Example 6-9 C source for lib2.sl (file lib2.c):
Example 6-10 C source for lib3.sl (file lib3.c):
Multiple initializers/terminators within the same load module (an executable or shared library) are called in an order following these rules:
For example, the linker command:
results in the following order when library is loaded:
and the following order when library is unloaded:
When multiple load modules have initializers/terminators, the following rules apply to ordering:
For example, given three libraries: libA.sl, libB.sl, libC.sl. If libA.sl were linked as (libB.sl and libC.sl are "dependent" libraries of libA.sl):
One possible ordering while loading is:
and while unloading is:
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||