On Solaris, these entry (initialization), exit (finilization) points can be encapsulated in either an array of function pointers or a single code block. With the help of link-editor (
ld
), we can write code to fire up during pre-loading, loading, and unloading of a shared object. Link-editor creates sections .preinit_array
, .init_array
, .init
, .initfirst
, .fini_array
and .fini
in the ELF object being built, based on the linker options and the compiler pragmas. Let's have a brief look at those sections in the following paragraphs:.preinit_array
section
A dynamic executable may provide pre-initialization functions, to get executed once the run-time linker has built the process image and performed the necessary relocations. As the name suggests, pre-initialization functions get executed before any other initialization functions. Dynamic libraries are not permitted to have pre-initialization functions.
The-z preinitarray=function,[function,..]
flag of link-editor lets us specify the names of the pre-initialization function(s). During linking, it will be encoded into.preinit_array
section of the dynamic object
The run-time linker (ld.so.1
) constructs a dependency ordered list of initialization routines from the dependencies that have been loaded, and executes them in the reverse topological order of the dependencies..init_array
section
The-z initarray=function,[function,..]
flag of link-editor lets us specify the names of the initialization function(s). During linking, it will be encoded into.init_array
section of the dynamic object. Dynamic executables and libraries are permittied to have initialization functions..initfirst
section
The link-editor has another flag-z initfirst
for fine granularity of control over the initialization routines. When the object is built with this flag, the run-time initialization occurs before the run-time initialization of any other objects brought into the process at the same time. In addition, the object run-time finalization will occur after the run-time finalization of any other objects removed from the process at the same time. Dynamic executables are not permitted to build with this linker flag..init
and.fini
sections
The.init
and.fini
provide a run-time initialization and termination code block, respectively. However, the compiler drivers typically supply.init
and.fini
sections with files they add to the beginning and end of your input file list. These files have the effect of encapsulating the .init and .fini code into individual functions. These functions are identified by the reserved symbol names_init
and_fini
respectively.
Sun Studio C/C++ compilers provide the pragmasinit
andfini
, for the developers to specify the initialization and termination code blocks in terms of functions. These pragmas must appear somewhere before the definition of the init/fini functions.
Syntax:#pragma init (function[,function..])
#pragma fini (function[,function..]).fini_array
section
As with initialization routines, we can also specify the finalization code to be executed, with the help of link-editor's-z initarray=function[,function..]
Finalization code will be called when a program terminates under program control or when the containing shared object is removed from memory. As with initialization functions, finalization functions are executed in the order processed by the link editor. In other words, the dynamic executable's.fini
section is called first, before its dependencies termination sections are executed
Let's put together the things we learned so far in an example.
Example 1. Creating init, fini sections with Sun Studio pragmas
% cat fileops.h2. Creating initialization, termination sections with linker options
FILE *fd;
void fileopen();
void fileclose();
void filewrite(FILE *, char *);
% cat fileops.c
#include <stdio.h>
#include "fileops.h"
#pragma init (fileopen)
#pragma fini (fileclose)
void fileopen() {
printf("\nInside fileopen() ..");
fd = fopen("/tmp/dummy", "a");
}
void fileclose() {
printf("\nInside fileclose() ..");
fclose(fd);
}
void filewrite(FILE *fd, char *string) {
fprintf(fd, string);
}
% cc -G -o libfileops.so fileops.c
% cat filedriver.c
#include <stdio.h>
#include "fileops.h"
int main() {
filewrite(fd, (char *)"Hey!");
return (0);
}
% cc -o driver -lfileops filedriver.c
%ls -l /tmp/dummy
/tmp/dummy: No such file or directory
% ./driver
Inside fileopen() ..
Inside fileclose() ..
% ls -l /tmp/dummy
-rw-rw-r-- 1 build engr 4 Jul 15 18:17 /tmp/dummy
% cat /tmp/dummy
Hey!
% elfdump libfileops.so
... some parts of the dump were elided ...
Relocation Section: .rela.init
type offset addend section with respect to
R_SPARC_WDISP30 0x44c 0 .rela.init fileopen
Relocation Section: .rela.fini
type offset addend section with respect to
R_SPARC_WDISP30 0x460 0 .rela.fini fileclose
... some parts of the dump were elided ...
Let's remove the
pragma
statements from fileops.c
and rebuild the libfileops
library, with -zinitarray=fileopen -zfiniarray=fileclose
linker flagsFinally, we can observe the sequence of initialization, termination calls, by setting the
% cat fileops.c
#include <stdio.h>
#include "fileops.h"
void fileopen() {
printf("\nInside fileopen() ..");
fd = fopen("/tmp/dummy", "a");
}
void fileclose() {
printf("\nInside fileclose() ..");
fclose(fd);
}
void filewrite(FILE *fd, char *string) {
fprintf(fd, string);
}
% cc -G -o libfileops.so -zinitarray=fileopen -zfiniarray=fileclose fileops.c
% elfdump libfileops.so
... some parts of the dump were elided ...
Relocation Section: .rela.initarray
type offset addend section with respect to
R_SPARC_32 0x10544 0 .rela.initarra fileopen
Relocation Section: .rela.finiarray
type offset addend section with respect to
R_SPARC_32 0x10548 0 .rela.finiarra fileclose
... some parts of the dump were elided ...
% ./driver
Inside fileopen() ..
Inside fileclose() ..
LD_DEBUG
environment variable of run-time linker to basic
.Reference:
% setenv LD_DEBUG basic
% ./driver
29503:
29503: configuration file=/var/ld/ld.config: unable to process file
29503:
29503: calling .init (from sorted order): /usr/lib/libc.so.1
29503:
29503: calling .init (done): /usr/lib/libc.so.1
29503:
29503: calling .init (from sorted order): ./libfileops.so
29503:
Inside fileopen() ..29503:
29503: calling .init (done): ./libfileops.so
29503:
29503: transferring control: ./driver
29503:
29503: calling .fini: ./libfileops.so
29503:
Inside fileclose() ..29503:
29503: calling .fini: /usr/lib/libc.so.1
29503:
Solaris Linker and Libraries Guide
[09/15/2005: Adam Levanthal posted some interesting content about
_init
, in his blog with title The mysteries of _init]_____________________
Technorati tags: Sun | Solaris | Linker | Programming
No comments:
Post a Comment