 |
» |
|
|
 |
This section describes the shl_load
family of shared library management routines.  |  |  |  |  | NOTE: You can use these routines in both 32-bit and 64-bit
mode. Support for these routines may be discontinues in a future
64-bit HP-UX release. If you use these routines in 64-bit mode,
consider converting your programs to the dl*
family of shared library management routines. |  |  |  |  |
The shl_load and cxxshl_load
Routines |  |
Explicitly loads a library. shl_t shl_load( const char * path, int flags, long address ) |
- path
A null-terminated character string containing the
path name of the shared library to load. - flags
Specifies when the symbols in the library should
be bound to addresses. It must be one of these values, defined in
<dl.h>: - BIND_IMMEDIATE
Bind the addresses of all symbols immediately upon
loading the library. - BIND_DEFERRED
Bind the addresses when they are first referenced.
Be aware that BIND_IMMEDIATE
causes the binding of all symbols, and the resolution of all imports,
even from older versioned modules in the shared library. If symbols
are not accessible because they come from old modules, they are
unresolved and shl_load
may fail. In addition to the above values, the flags
parameter can be ORed with the following values: - BIND_NONFATAL
Allow binding of unresolved symbols. - BIND_VERBOSE
Make dynamic loader display verbose messages when
binding symbols. - BIND_FIRST
Insert the loaded library before all others in the
current link order. - DYNAMIC_PATH
Causes the dynamic loader to perform dynamic library
searching when loading the library. The +s
and +b options to the ld
command determine the directories the linker searches. This is the
default mode for the 64-bit mode linker if +compat
linker option is not specified. - BIND_NOSTART
Causes the dynamic loader to not
call the initializer, even if one is declared for the library, when
the library is loaded or on a future call to shl_load
or dlopen. This also inhibits a
call to the initializer when the library is unloaded. - BIND_RESTRICTED
Causes the search for a symbol definition to be
restricted to those symbols that were visible when the library was
loaded. - BIND_TOGETHER
Causes the library being loaded and all its dependent
libraries to be bound together rather than each independently. Use
this when you have interdependent libraries and you are using BIND_FIRST. - BIND_BREADTH_FIRST
64-bit mode only: Causes the dependent libraries to be loaded breadth first.
By default, the 64-bit mode shl_load
loads dependent libraries depth-first.
These flags are discussed in detail
in“shl_load Example ”. - address
Specifies the virtual address at which to attach
the library. Set this parameter to 0
(zero) to tell the system to choose the best location. This argument
is currently ignored; mapping a library at a user-defined address
is not currently supported.
If successful, shl_load
returns a shared library handle of type shl_t.
This address can be used in subsequent calls to shl_close,
shl_findsym, shl_gethandle,
and shl_gethandle_r. Otherwise,
shl_load returns
a shared library handle of NULL
and sets errno
to one of these error codes (from <errno.h>): Title not available (Return Value ) - ENOEXEC
The specified path is
not a shared library, or a format error was detected in this or
another library. - ENOSYM
A symbol needed by this library or another library
which this library depends on could not be found. - ENOMEM
There is insufficient room in the address space
to load the shared library. - EINVAL
The requested shared library address was invalid. - ENOENT
The specified path does
not exist. - EACCESS
Read or execute permission is denied for the specified
path.
A program needs to explicitly load a library only if the library
was not linked with the program. This typically occurs only when
the library cannot be known at link time — for example,
when writing programs that must support future graphics devices. However, programs are not restricted to using shared libraries
only in that situation. For example, rather than linking with any
required libraries, a program could explicitly load libraries as
they are needed. One possible reason for doing this is to minimize
virtual memory overhead. To keep virtual memory resource usage to
a minimum, a program could load libraries with shl_load
and unload with shl_unload
when the library is no longer needed. However, it is normally not
necessary to incur the programming overhead of loading and unloading
libraries yourself for the sole reason of managing system resources. Note that if shared library initializers have been declared
for an explicitly loaded library, they are called after the library
is loaded. For details, see “Initializers for Shared Libraries”. To explicitly load a shared library, use the shl_load
routine. If loading a C++ library, use the cxxshl_load
routine. This ensures that constructors of nonlocal static objects
are executed when the library is loaded. The syntax of cxxshl_load
is the same as that of shl_load. In 64-bit mode, shl_load
lets you load a compatibility or standard mode shared libraries.
The BIND_BREADTH_FIRST flag overrides
the default depth-first loading mechanism. Since the library was not specified at link time, the program
must get the library name at run time. Here are some practical ways
to do this: Hard-code the library name into the
program (the easiest method). Get the library name from an environment variable
using the getenv
library routine (see getenv(3C)). Get the library path name from the command line
through argv. Read the library name from a configuration file. Prompt for the library path name at run time.
If successful, shl_load
returns a shared library handle (of type shl_t),
which uniquely identifies the library. This handle can then be passed
to the shl_findsym
or shl_unload
routine. Once a library is explicitly loaded, use the shl_findsym
routine to get pointers to functions or data contained in the library;
then call or reference them through the pointers. This is described
in detail in“The shl_findsym Routine ”. The following example shows the source for a function named
load_lib that
explicitly loads a library specified by the user. The user can specify
the library in the environment variable SHLPATH
or as the only argument on the command line. If the user chooses
neither of these methods, the function prompts for the library path
name. The function then attempts to load the specified library.
If successful, it returns the shared library handle, of type shl_t.
If an error occurs, it displays an error message and exits. This
function is used later in “The shl_findsym Routine ”. Example 6-13 load_lib — Function
to Load a Shared Library  |
#include <stdio.h> /* contains standard I/O defs */ #include <stdlib.h> /* contains getenv definition */ #include <dl.h> /* contains shared library type defs */ shl_t load_lib(int argc, char * argv[]) /* pass argc and argv from main */ { shl_t lib_handle; /* temporarily holds library handle */ char lib_path[MAXPATHLEN]; /* holds library path name */ char *env_ptr; /* points to SHLPATH variable value */ /* * Get the shared library path name: */ if (argc > 1) /* library path given on command line */ strcpy(lib_path, argv[1]); else /* get lib_path from SHLPATH variable */ { env_ptr = getenv("SHLPATH"); if (env_ptr != NULL) strcpy(lib_path, env_ptr); else /* prompt user for shared library path */ { printf("Shared library to use >> "); scanf("%s", lib_path); } } /* * Dynamically load the shared library using BIND_IMMEDIATE binding: */ lib_handle = shl_load( lib_path, BIND_IMMEDIATE, 0); if (lib_handle == NULL) perror("shl_load: error loading library"), exit(1); return lib_handle; } |
If you load a shared library with the BIND_IMMEDIATE
flag and the library contains unresolved symbols, the load fails
and sets errno
to ENOSYM. ORing
BIND_NONFATAL
with BIND_IMMEDIATE
causes shl_load
to allow the binding of unresolved symbols to be deferred if their
later use can be detected — for example: shl_t libH; . . . libH = shl_load("libxyz.sl", BIND_IMMEDIATE | BIND_NONFATAL, 0); |
However, data symbol binding cannot be deferred, so using
the BIND_NONFATAL
modifier does not allow the binding of unresolved data symbols. If BIND_VERBOSE
is ORed with the flags parameter, the
dynamic loader displays messages for all unresolved symbols. This
option is useful to see exactly which symbols cannot be bound. Typically,
you would use this with BIND_IMMEDIATE
to debug unresolved symbols — for example: shl_t libH; . . . libH = shl_load("libxyz.sl", BIND_IMMEDIATE | BIND_VERBOSE, 0); |
If BIND_FIRST
is ORed with the flags parameter, the
loaded library is inserted before all other loaded shared libraries
in the symbol resolution search order. This has the same effect
as placing the library first in the link order — that is,
the library is searched before other libraries when resolving symbols.
This is used with either BIND_IMMEDIATE
or BIND_DEFERRED
— for example: shl_t libH; . . . libH = shl_load("libpdq.sl", BIND_DEFERRED | BIND_FIRST, 0); |
BIND_FIRST
is typically used when you want to make the symbols in a particular
library more visible than the symbols of the same name in other
libraries. Compare this with the default behavior, which is to append
loaded libraries to the link order. The flag DYNAMIC_PATH
can also be ORed with the flags parameter,
causing the dynamic loader to search for the library using a path
list specified by the +b
option at link time or the SHLIB_PATH
environment variable at run time. The flag BIND_NOSTART
inhibits execution of initializers for the library. This flag is most useful with the BIND_DEFERRED
flag; it has no effect with BIND_IMMEDIATE.
It is also useful with the BIND_NONFATAL
flag. When used with only the BIND_DEFERRED
flag, it has this behavior: When a symbol is referenced and needs
to be bound, this flag causes the search for the symbol definition
to be restricted to those symbols that were visible when the library
was loaded. If a symbol definition cannot be found within this restricted
set, it results in a run-time symbol-binding error. When used with BIND_DEFERRED
and the BIND_NONFATAL
modifier, it has the same behavior, except that when a symbol definition
cannot be found, the dynamic loader will then look in the global
symbol set. If a definition still cannot be found within the global
set, a run-time symbol-binding error occurs. BIND_TOGETHER
modifies the behavior of BIND_FIRST.
When the library being loaded has dependencies, BIND_FIRST
causes each dependent library to be loaded and bound separately.
If the libraries have interdependencies, the load may fail because
the needed symbols are not available when needed. BIND_FIRST | BIND_TOGETHER
causes the library being loaded and its dependent libraries to be
bound all at the same time, thereby resolving interdependencies.
If you are not using BIND_FIRST,
libraries are bound together by default so this option has no effect. BIND_BREADTH_FIRST Modifier64-bit mode only: This flag causes the dependent libraries to be loaded breadth
first. By default, the 64-bit mode shl_load
loads dependent libraries depth-first. This modifier overrides the
default load order. Suppose you have the libraries libE.sl,
libF.sl, and
libG.sl. The
libE library
depends on libF
and libF depends
on libG. In addition,
libG depends
on libF—libF
and libG are
interdependent. Your program loads libE.sl
with shl_load(). When using BIND_DEFERRED
or BIND_IMMEDIATE
without BIND_FIRST,
these libraries are loaded such that all symbols are visible and
the interdependencies are resolved: shl_t libE; libE = shl_load("libE.sl", BIND_IMMEDIATE, 0); shl_load succeeds. |
When using BIND_IMMEDIATE | BIND_FIRST,
however, libG
is loaded and bound first and since it depends on libF,
an error results because the needed symbols in libF
are not yet available: libE = shl_load("libE.sl", BIND_IMMEDIATE | BIND_FIRST, 0); shl_load fails. |
Using BIND_IMMEDIATE | BIND_FIRST | BIND_TOGETHER
loads libE, libF,
and libG together
and correctly resolves all symbols: libE = shl_load("libE.sl", BIND_IMMEDIATE | BIND_FIRST | BIND_TOGETHER, 0); shl_load succeeds. |
The shl_findsym Routine |  |
Obtains the address of an exported symbol from a shared library.
To call a routine or access data in an explicitly loaded library,
first get the address of the routine or data with shl_findsym. int shl_findsym( shl_t * handle, const char * sym, short type, void * value ) |
- handle
A pointer to a shared library
handle of the library to search for the symbol name sym.
This handle could be obtained from the shl_get
routine (described in the “The shl_get and shl_get_r Routines”). handle
can also point to: - NULL
If a pointer to NULL
is specified, shl_findsym
searches all loaded libraries for sym.
If sym is found, shl_findsym
sets handle to a pointer to the handle
of the shared library containing sym.
This is useful for determining which library a symbol resides in.
For example, the following code sets handle
to a pointer to the handle of the library containing symbol _foo: shl_t handle; handle = NULL; shl_findsym(&handle,"_foo",...); |
- PROG_HANDLE
This constant, defined in dl.h,
tells shl_findsym
to search for the symbol in the program itself. This way, any symbols
exported from the program can be accessed explicitly.
- sym
A null-terminated character string containing the
name of the symbol to search for. - type
The type of symbol to look for. It must be one of
the following values, defined in <dl.h>: - TYPE_PROCEDURE
Look for a function or procedure. - TYPE_DATA
Look for a symbol in the data segment (for example,
variables). - TYPE_UNDEFINED
Look for any symbol. - TYPE_STORAGE
32-bit mode only. - TYPE_TSTORAGE
32-bit mode only.
- value
A pointer in which shl_findsym
stores the address of sym, if found.
If successful, shl_findsym
returns an integer (int)
value zero. If shl_findsym
cannot find sym, it returns -1
and sets errno
to zero. If any other errors occur, shl_findsym
returns -1 and sets errno
to one of these values (defined in <errno.h>): - ENOEXEC
A format error was detected in the specified library. - ENOSYM
A symbol on which sym
depends could not be found. - EINVAL
The specified handle
is invalid.
To call a routine or access data in an explicitly loaded library,
first get the address of the routine or data with shl_findsym. To call a routine in an explicitly loaded library declare a pointer to a function of the same type as the function
in the shared library using shl_findsym
with the type parameter set to TYPE_PROCEDURE,
find the symbol in the shared library and assign its address to
the function pointer declared in Step 1 call the pointer to the function obtained in Step
2, with the correct number and type of arguments
To access data in an explicitly loaded library declare a pointer to a data structure of the same type as
the data structure to access in the library using shl_findsym
with the type parameter set to TYPE_DATA,
find the symbol in the shared library and assign its address to
the pointer declared in Step 1 access the data through the pointer obtained in
Step 2
Suppose you have a set of libraries that output to various
graphics devices. Each graphics device has its own library. Although
the actual code in each library varies, the routines in these shared
libraries have the same name and parameters, and the global data
is the same. For instance, they all have these routines and data: - gopen()
opens the graphics device for output - gclose()
closes the graphics device - move2d(x,y)
moves to pixel location x,y - draw2d(x,y)
draws to pixel location x,y
from current x,y - maxX
contains the maximum X pixel location on the output
device - maxY
contains the maximum Y pixel location on the output
device
The following example shows a C program that can load any
supported graphics library at run time, and call the routines and
access data in the library. The program calls load_lib
(see Example 6-13 “load_lib — Function
to Load a Shared Library ”) to load
the library. Example 6-14 Load a Shared Library and
Call Its Routines and Access Its Data  |
#include <stdio.h> /* contains standard I/O defs */ #include <stdlib.h> /* contains getenv definition */ #include <dl.h> /* contains shared library type defs */ /* * Define linker symbols: */ #define GOPEN "gopen" #define GCLOSE "gclose" #define MOVE2D "move2d" #define DRAW2D "draw2d" #define MAXX "maxX" #define MAXY "maxY" shl_t load_lib(int argc, char * argv[]); main(int argc, char * argv[]) { shl_t lib_handle; /* handle of shared library */ int (*gopen)(void); /* opens the graphics device */ int (*gclose)(void); /* closes the graphics device */ int (*move2d)(int, int); /* moves to specified x,y location */ int (*draw2d)(int, int); /* draw line to specified x,y location*/ int *maxX; /* maximum X pixel on device */ int *maxY; /* maximum Y pixel on device */ lib_handle = load_lib(argc, argv); /* load required shared library */ /* * Get addresses of all functions and data that will be used: */ if (shl_findsym(&lib_handle, GOPEN, TYPE_PROCEDURE, (void *) &gopen)) perror("shl_findsym: error finding function gopen"), exit(1); if (shl_findsym(&lib_handle, GCLOSE, TYPE_PROCEDURE, (void *) &gclose)) perror("shl_findsym: error finding function gclose"), exit(1); if (shl_findsym(&lib_handle, MOVE2D, TYPE_PROCEDURE, (void *) &move2d)) perror("shl_findsym: error finding function move2d"), exit(1); if (shl_findsym(&lib_handle, DRAW2D, TYPE_PROCEDURE, (void *) &draw2d)) perror("shl_findsym: error finding function draw2d"), exit(1); if (shl_findsym(&lib_handle, MAXX, TYPE_DATA, (void *) &maxX)) perror("shl_findsym: error finding data maxX"), exit(1); if (shl_findsym(&lib_handle, MAXY, TYPE_DATA, (void *) &maxY)) perror("shl_findsym: error finding data maxY"), exit(1); /* * Using the routines, draw a line from (0,0) to (maxX,maxY): */ (*gopen)(); /* open the graphics device */ (*move2d)(0,0); /* move to pixel 0,0 */ (*draw2d)(*maxX,*maxY); /* draw line to maxX,maxY pixel */ (*gclose)(); /* close the graphics device */ }
|
 |
Shown below is the compile line for this program, along with
the commands to set SHLPATH
appropriately before running the program. SHLPATH
is declared and used by load_lib(),
defined in “The shl_load and cxxshl_load
Routines ” example.
Notice that load_lib()
is compiled here along with this program. Finally, this example
assumes you have created a graphics library, libgrphdd.sl: $ cc -Aa -o drawline shl_findsym.c load_lib.c -ldld $ SHLPATH=/usr/lib/libgrphdd.sl $ export SHLPATH $ drawline |
The shl_get and shl_get_r Routines |  |
Obtains information on the currently loaded libraries. int shl_get( int index, struct shl_descriptor **desc ) |
- index
Specifies an ordinal number of the shared library
in the process. For libraries loaded implicitly
(at startup time), index is the ordinal
number of the library as it appeared on the command line. For example,
if libc was the
first library specified on the ld
command line, then libc
has an index of 1. For explicitly loaded
libraries, index corresponds to the order
in which the libraries were loaded, starting after the ordinal number
of the last implicitly loaded library. Two index
values have special meaning: - 0
Refers to the main program itself - -1
Refers to the dynamic loader (dld.sl).
A shared library's index can be
modified during program execution by either of the following events: The program loads a shared library
with the BIND_FIRST
modifier to shl_load.
This increments all the shared library indexes by one. The program unloads a shared library with shl_unload.
Any libraries following the unloaded library have their index decremented
by one.
- desc
Returns a pointer to a statically allocated buffer
(struct shl_descriptor **)
containing a shared library descriptor. The structure contains these
important fields: - tstart
The start address (unsigned long)
of the shared library text segment. - tend
The end address (unsigned long)
of the shared library text segment. - dstart
The start address (unsigned long)
of the shared library data segment. - dend
The end address (unsigned long)
of the shared library bss segment. The data and bss segments together
form a contiguous memory block starting at dstart
and ending at dend. - handle
The shared library's handle (type shl_t). - filename
A character array containing the library's path
name as specified at link time or at explicit load time. - initializer
A pointer to the shared library's initializer routine
(see “Initializers for Shared Libraries”. It is NULL
if there is no initializer. This field is useful for calling the
initializer if it was disabled by the BIND_NOSTART
flag to shl_load. If the shared library has multiple initializers, this field
will also be set to NULL.
Multiple initializers can be found with shl_getsymbols,
described later in this chapter.
This buffer is statically allocated. Therefore, if a program
intends to use any of the members of the structure, the program
should make a copy of the structure before the next call to shl_get.
Otherwise, shl_get
will overwrite the static buffer when called again.
If successful, shl_get
returns an integer value 0. If the index
value exceeds the number of currently loaded libraries, shl_get
returns -1 and sets errno
to EINVAL. To obtain information on currently loaded libraries, use the
shl_get function.
If you are programming in a threaded environment, use the thread-safe
version shl_get_r
which is the same as shl_get
in all other respects. (See Programming with Threads
on HP-UX for more information about threads.) Other than obtaining interesting information, this routine
is of little use to most programmers. A typical use might be to
display the names and starting/ending address of all shared libraries
in a process's virtual memory address space. The function show_loaded_libs
shown below displays the name and start and end address of the text
and data/bss segments the library occupies in a process's virtual
address space. Example 6-15 show_loaded_libs — Display
Library Information #include <stdio.h> /* contains standard I/O defs */ #include <dl.h> /* contains shared library type defs */ void show_loaded_libs(void) { int idx; struct shl_descriptor *desc; printf("SUMMARY of currently loaded libraries:\n"); printf("%-25s %10s %10s %10s %10s\n", "___library___", "_tstart_", "__tend__", "_dstart_", "__dend__"); idx = 0; for (idx = 0; shl_get(idx, &desc) != -1; idx++) printf("%-25s %#10lx %#10lx %#10lx %#10lx\n", desc->filename, desc->tstart, desc->tend, desc->dstart, desc->dend); } |
Calling this function from a C program compiled with shared
libc and libdld
produced the following output: SUMMARY of currently loaded libraries: ___library___ _tstart_ __tend__ _dstart_ __dend__ ./a.out 0x1000 0x1918 0x40000000 0x40000200 /usr/lib/libdld.sl 0x800ac800 0x800ad000 0x6df62800 0x6df63000 /usr/lib/libc.sl 0x80003800 0x80091000 0x6df63000 0x6df85000 |
The shl_gethandle and shl_gethandle_r
Routines |  |
Returns descriptor information about a loaded shared library. int shl_gethandle( shl_t handle, struct shl_descriptor **desc ) |
- handle
The handle of the shared library you want information
about. This handle is the same as that
returned by shl_load. - desc
Points to shared library descriptor information
— the same information returned by the shl_get
routine. The buffer used to store this desc
information is static, meaning that subsequent calls to shl_gethandle
will overwrite the same area with new data. Therefore, if you need
to save the desc information, copy it
elsewhere before calling shl_gethandle
again.
If handle is not valid, the routine
returns -1 and sets errno
to EINVAL. Otherwise,
shl_gethandle
returns 0. The shl_gethandle
routine returns descriptor information about a loaded shared library.
If you are programming in a threaded environment, use the thread-safe
version shl_gethandle_r
which is the same as shl_gethandle
in all other respects. (See Programming with Threads
on HP-UX for more information about threads.) The following function named show_lib_info
displays information about a shared library, given the library's
handle. Example 6-16 show_lib_info —
Display Information for a Shared Library #include <stdio.h> #include <dl.h> int show_lib_info(shl_t libH) { struct shl_descriptor *desc; if (shl_gethandle(libH, &desc) == -1) { fprintf(stderr, "Invalid library handle.\\n"); return -1; } printf("library path: %s\\n", desc->filename); printf("text start: %#10lx\\n", desc->tstart); printf("text end: %#10lx\\n", desc->tend); printf("data start: %#10lx\\n", desc->dstart); printf("data end: %#10lx\\n", desc->dend); return 0; } |
The shl_definesym Routine |  |
Adds new symbols to the global shared library symbol table. int shl_definesym( const char *sym, short type, long value, int flags ) |
- sym
A null-terminated string containing the name of
the symbol to change or to add to the process's shared library symbol
table. - type
The type of symbol — either TYPE_PROCEDURE
or TYPE_DATA. - value
If value falls in the
address range of a currently loaded library, an association will
be made and the symbol is undefined when the library is unloaded.
(Note that memory dynamically allocated with malloc(3C)
does not fall in the range of any
library.) The defined symbol may be overridden by a subsequent call
to this routine or by loading a more visible library that provides
a definition for the symbol. - flags
Must be set to zero.
If successful, shl_definesym
returns 0. Otherwise, it returns -1 and sets errno
accordingly. See shl_definesym(3X) for details. The shl_definesym
function allows you to add a new symbol to the global shared library
symbol table. Use of this routine will be unnecessary for most programmers. There are two main reasons to add or change shared library
symbol table entries: to generate symbol definitions as
the program runs — for example, aliasing one symbol with
another to override a current definition
Symbol definitions in the incomplete executable may also be
redefined with certain restrictions: The incomplete executable always uses
its own definition for any data (storage) symbol, even if a more
visible one is provided. The incomplete executable only uses a more visible
code symbol if the main program itself does not provide a definition.
The shl_getsymbols Routine |  |
The shl_getsymbols
function retrieves symbols that are imported (referenced) or exported
(defined) by a shared library. This information is returned in an
allocated array of records, one for each symbol. Most programmers
do not need to use this routine. int shl_getsymbols( shl_t handle, short type, int flags, void * (*memfunc)(), struct shl_symbol **symbols ) |
- handle
The handle of the shared library whose symbols you
want to retrieve. If handle is NULL,
shl_getsymbols
returns symbols that were defined with the shl_definesym
routine. - type
Defines the type of symbol to retrieve. It must
be one of the following values, which are defined as constants in
<dl.h>: - TYPE_PROCEDURE
Retrieve only function or procedure symbols. - TYPE_DATA
Retrieve only symbols from the data segment (for
example, variables). - TYPE_UNDEFINED
Retrieve all symbols, regardless
of type. - TYPE_STORAGE
32-bit mode only. - TYPE_TSTORAGE
32-bit mode only.
- flags
Defines whether to retrieve import or export symbols
from the library. An import symbol is an
external reference made from a library. An export symbol
is a symbol definition that is referenced outside the library. In
addition, any symbol defined by shl_definesym
is an export symbol. Set this argument to one of the following values
(defined in <dl.h>): - IMPORT_SYMBOLS
To return import symbols. - EXPORT_SYMBOLS
To return export symbols. - INITIALIZERS
To return initializer symbols.
One of the following modifiers can be ORed with both the EXPORT_SYMBOLS
and the INITIALIZERS
flags: - NO_VALUES
Do not calculate the value
field of the shl_symbol
structure for symbols. The value
field has an undefined value. - GLOBAL_VALUES
For symbols that are defined in multiple libraries,
this flag causes shl_getsymbols
to return the most-visible occurrence, and to set the value
and handle fields
of the shl_symbol
structure (defined in the description of the symbols
parameter).
- memfunc
Points to a function that has the same interface
(calling conventions and return value) as malloc(3C).
The shl_getsymbols
function uses this function to allocate memory to store the array
of symbol records, symbols. - symbols
This points to an array of symbol records for all
symbols that match the criteria determined by the type
and value parameters. The type of these
records is struct shl_symbol,
defined in <dl.h>
as: struct shl_symbol { char * name; short type; void * value; shl_t handle; }; |
The members of this structure are described in “The shl_symbol Structure”.
If successful, shl_getsymbols
returns the number of symbols found; otherwise, -1 is returned
and shl_getsymbols
sets errno to
one of these values: - ENOEXEC
A format error was detected in the specified library. - ENOSYM
Some symbol required by the shared library could
not be found. - EINVAL
The specified handle
is invalid. - ENOMEM
memfunc failed to allocate
the requested memory.
The members of the shl_symbol
structure are defined as follows: - name
Contains the name of a symbol. - type
Contains the symbol's type: TYPE_PROCEDURE,
TYPE_DATA, or
TYPE_STORAGE.
TYPE_STORAGE
is a data symbol used for C uninitialized global variables or FORTRAN
common blocks. - value
Contains the symbol's address. It is valid only
if EXPORT_SYMBOLS
is specified without the NO_VALUES
modifier. - handle
Contains the handle of the shared library in which
the symbol is found, or NULL
in the case of symbols defined by shl_definesym.
It is valid only if EXPORT_SYMBOLS
or INITIALIZERS
were requested without the NO_VALUES
modifier. It is especially useful when used with the GLOBAL_VALUES
modifier, allowing you to determine the library in which the most-visible
definition of a symbol occurs.
Example 6-17 “show_symbols — Display
Shared Library Symbols ” shows
the source for a function named show_symbols
that displays shared library symbols. The syntax of this routine
is defined as: int show_symbols(shl_t hndl, short type, int flags) |
- hndl
The handle of the shared library whose symbols you
want to display. - type
The type of symbol you want to display. This is
the same as the type parameter to shl_getsymbols
and can have these values: TYPE_PROCEDURE,
TYPE_DATA, or
TYPE_UNDEFINED.
If it is TYPE_UNDEFINED,
show_symbols
displays the type of each symbol. - flags
This is the same as the flags
parameter. It can have the value EXPORT_SYMBOLS
or IMPORT_SYMBOLS.
In addition, it can be ORed with NO_VALUES
or GLOBAL_VALUES.
If EXPORT_SYMBOLS
is specified without being ORed with NO_VALUES,
show_symbols
displays the address of each symbol.
Example 6-17 show_symbols — Display
Shared Library Symbols  |
#include <dl.h> #include <stdio.h> #include <stdlib.h> int show_symbols(shl_t hndl, short type, int flags) { int num_symbols, sym_idx; struct shl_symbol *symbols, *orig_symbols; num_symbols = shl_getsymbols(hndl, type, flags, malloc, &symbols); if (num_symbols < 0) { printf("shl_getsymbols failed\n"); exit(1); } orig_symbols = symbols; for (sym_idx = 0; sym_idx < num_symbols; sym_idx++) { printf(" %-30s", symbols->name); /* display symbol name */ if (type == TYPE_UNDEFINED) /* display type if TYPE_UNDEFINED */ switch (symbols->type) { case TYPE_PROCEDURE: printf(" PROCEDURE"); break; case TYPE_DATA: printf(" DATA "); break; case TYPE_STORAGE: printf(" STORAGE "); } if ((flags & EXPORT_SYMBOLS) /* export symbols requested */ && (flags & NO_VALUES)==0) /* NO_VALUES was NOT specified */ printf(" 0x%8X", symbols->value); /* so display symbol's address */ printf("\n"); /* terminate output line */ symbols++; /* move to next symbol record */ } free(orig_symbols); /* free memory allocated by malloc */ return num_symbols; /* return the number of symbols */ } |
 |
The following example shows the source for a program named
show_all.c that
calls show_symbols
to show all imported and exported symbols for every loaded shared
library. It uses shl_get
to get the library handles of all loaded libraries. Example 6-18 show_all — Use show_symbols
to Show All Symbols #include <dl.h> #include <stdio.h> /* prototype for show_syms */ int show_syms(shl_t hndl, short type, int flags); main() { int idx, num_syms; struct shl_descriptor * desc; for (idx=0; shl_get(idx, &desc) != -1; idx++) /* step through libs */ { printf("[%s]\n", desc->filename); /* show imports & exports for each */ printf(" Imports:\n"); num_syms = show_symbols(desc->handle, TYPE_UNDEFINED, IMPORT_SYMBOLS); printf(" TOTAL SYMBOLS: %d\n", num_syms); printf(" Exports:\n"); num_syms = show_symbols(desc->handle, TYPE_UNDEFINED, EXPORT_SYMBOLS); printf(" TOTAL SYMBOLS: %d\n", num_syms); } }
|
The show_all
program shown above was compiled with the command: $ cc -Aa -o show_all show_all.c show_symbols.c -ldld |
 |  |  |  |  | NOTE: The following output for the example will differ in
64-bit mode. For example, STORAGE
is not supported. |  |  |  |  |
The output produced by running this program is shown below: [show_all] Imports: errno STORAGE _start PROCEDURE malloc PROCEDURE free PROCEDURE exit PROCEDURE printf PROCEDURE shl_get PROCEDURE shl_getsymbols PROCEDURE __d_trap PROCEDURE TOTAL SYMBOLS: 9 Exports: environ DATA 0x40001018 errno STORAGE 0x400011CC _SYSTEM_ID DATA 0x40001008 __dld_loc STORAGE 0x400011C8 _FPU_MODEL DATA 0x4000100C _end DATA 0x400011D0 _environ DATA 0x40001018 __d_trap PROCEDURE 0x7AFFF1A6 main PROCEDURE 0x7AFFF1BE TOTAL SYMBOLS: 9 [/usr/lib/libc.1] Imports: _res_rmutex STORAGE errno STORAGE _regrpc_rmutex STORAGE _yellowup_rmutex STORAGE _FPU_MODEL STORAGE _environ_rmutex STORAGE _iop_rmutex STORAGE _rpcnls_rmutex STORAGE _switch_rmutex STORAGE _mem_rmutex STORAGE _dir_rmutex STORAGE |
The shl_unload and cxxshl_unload
Routines |  |
Unloads or frees up space for a shared library. int shl_unload(shl_t handle) - handle
The handle of the shared library you wish to unload.
The handle value is obtained from a previous
call to shl_load,
shl_findsym,
or shl_get.
If successful, shl_unload
returns 0. Otherwise, shl_unload
returns -1 and sets errno
to an appropriate value: - EINVAL
Indicates the specified handle
is invalid.
To unload a shared library, use the shl_unload
function. One reason to do this is to free up the private copy of
shared library data and swap space allocated when the library was
loaded with shl_load.
(This is done automatically when a process exits.) Another reason for doing this occurs if a program needs to
replace a shared library. For example, suppose you implement some
sort of shell or interpreter, and you want to load and execute user
"programs" which are actually shared libraries.
So you load one program, look up its entry point, and call it. Now
you want to run a different program. If you do not unload the old
one, its symbol definitions might get in the way of the new library.
So you should unload it before loading the new library. Note that if shared library initializers have been declared
for a shared library, they will be called when the shared library
is explicitly unloaded. For details, see “Initializers for Shared Libraries”. If unloading a C++ library, use the cxxshl_unload
routine. This ensures that destructors of nonlocal static objects
are executed when the library is unloaded. The syntax of cxxshl_unload
is the same as that of shl_unload. When a library is unloaded, existing linkages to symbols in
an unloaded library are not invalidated. Therefore,
the programmer must ensure that the program does not reference symbols
in an unloaded library as undefined behavior will result. In general,
this routine is recommended only for experienced programmers. In 32-bit mode the shl_unload
routine unloads a shared library irrespective of whether other shared
libraries depend on it. In 64-bit mode shl_unload
unloads a shared library only if no other shared library depend
on it.
|