DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH PRINT BOOK
 
Object files

Initialization and termination functions

After the dynamic linker has built the process image and performed the relocations, each shared object and the executable file get the opportunity to execute some initialization functions. All shared object initializations happen before the executable file gains control.

Before the initialization functions for any object A is called, the initialization functions for any other objects that object A depends on are called. For these purposes, an object A depends on another object B, if B appears in A's list of needed objects (recorded in the DT_NEEDED entries of the dynamic structure). The order of initialization for circular dependencies is undefined.

The initialization of objects occurs by recursing through the needed entries of each object. The initialization functions for an object are invoked after the needed entries for that object have been processed. The order of processing among the entries of a particular list of needed objects is unspecified.


NOTE: Each processor supplement may optionally further restrict the algorithm used to determine the order of initialization. Any such restriction, however, may not conflict with the rules described by this specification.

The following example illustrates two of the possible correct orderings which can be generated for the example NEEDED lists. In this example the a.out is dependent on b, d, and e. b is dependent on d and f, while d is dependent on e and g. From this information a dependency graph can be drawn. The above algorithm on initialization will then allow the following specified initialization orderings among others.

Initialization ordering example

Similarly, shared objects and executable files may have termination functions, which are executed with the atexit(BA_OS) mechanism after the base process begins its termination sequence. The termination functions for any object A must be called before the termination functions for any other objects that object A depends on. For these purposes, an object A depends on another object B, if B appears in A's list of needed objects (recorded in the DT_NEEDED entries of the dynamic structure). The order of termination for circular dependencies is undefined.

Finally, an executable file may have pre-initialization functions. These functions are executed after the dynamic linker has built the process image and performed relocations but before any shared object initialization functions. Pre-initialization functions are not permitted in shared objects.


NOTE: Complete initialization of system libraries may not have occurred when pre-initializations are executed, so some features of the system may not be available to pre-initialization code. In general, use of pre-initialization code can be considered portable only if it has no dependencies on system libraries.

The dynamic linker ensures that it will not execute any initialization, pre-initialization, or termination functions more than once.

Shared objects designate their initialization and termination code in one of two ways. First, they may specify the address of a function to execute via the DT_INIT and DT_FINI entries in the dynamic structure, described in ``Dynamic section''.

Shared objects may also (or instead) specify the address and size of an array of function pointers. Each element of this array is a pointer to a function to be executed by the dynamic linker. Each array element is the size of a pointer in the programming model followed by the object containing the array. The address of the array of initialization function pointers is specified by the DT_INIT_ARRAY entry in the dynamic structure. Similarly, the address of the array of pre-initialization functions is specified by DT_PREINIT_ARRAY and the address of the array of termination functions is specified by DT_FINI_ARRAY. The size of each array is specified by the DT_INIT_ARRAYSZ, DT_PREINIT_ARRAYSZ and DT_FINI_ARRAYSZ entries.

The functions whose addresses are contained in the arrays specified by DT_INIT_ARRAY and by DT_PREINIT_ARRAY are executed by the dynamic linker in the same order in which their addresses appear in the array; those specified by DT_FINI_ARRAY are executed in reverse order.

If an object contains both DT_INIT and DT_INIT_ARRAY entries, the function referenced by the DT_INIT entry is processed before those referenced by the DT_INIT_ARRAY entry for that object. If an object contains both DT_FINI and DT_FINI_ARRAY entries, the functions referenced by the DT_FINI_ARRAY entry are processed before the one referenced by the DT_FINI entry for that object.


NOTE: Although the atexit(BA_OS) termination processing normally will be done, it is not guaranteed to have executed upon process death. In particular, the process will not execute the termination processing if it calls _exit [see exit(BA_OS)] or if the process dies because it received a signal that it neither caught nor ignored.

The processor supplement for each processor specifies whether the dynamic linker is responsible for calling the executable file's initialization function or registering the executable file's termination function with atexit(BA_OS). Termination functions specified by users via the atexit(BA_OS) mechanism must be executed before any termination functions of shared objects.


Previous topic: Hashing function

© 2005 The SCO Group, Inc. All rights reserved.
SCO OpenServer Release 6.0.0 -- 02 June 2005