HP-UX Linker and Libraries User's Guide
wrapper routine and the corresponding routine from the C library are copied into the a.out file.
If, on the other hand, a shared wrapper library and archive C library are specified, in that order,
then all routines that can be referenced by any routine in the wrapper library are copied from the
C library. To avoid this, link with archive or shared versions for both the wrapper library and C
library, or use an archive version of the wrapper library and a shared version of the C library.
Absolute Virtual Addresses
Writing code that relies on the linker to locate a symbol in a particular location or in a particular
order in relation to other symbols is known as making an implicit address dependency. Because
of the nature of shared libraries, the linker cannot always preserve the exact ordering of symbols
declared in shared libraries. In particular, variables declared in a shared library may be located
far from the main program's virtual address space, and they may not reside in the same relative
order within the library as they were linked. Therefore, code that has implicit address dependencies
may not work as expected with shared libraries.
An example of an implicit address dependency is a function that assumes that two global variables
that were defined adjacently in the source code is actually adjacent in virtual memory. Because
the linker may rearrange data in shared libraries, this is no longer guaranteed. Another example
is a function that assumes variables it declares statically (for example, C static variables) reside
below the reserved symbol _end in memory (see end(3)). In general, it is a bad idea to depend
on the relative addresses of global variables, because the linker may move them around.
In assembly language, using the address of a label to calculate the size of the immediately preceding
data structure is not affected: the assemblers still calculate the size correctly.
Stack Usage
To load shared libraries, a program must have a copy of the dynamic loader (dld.so) mapped
into its address space. This copy of the dynamic loader shares the stack with the program. The
dynamic loader uses the stack during startup and whenever a program calls a shared library
routine for the first time. If you specify -B immediate, the dynamic loader only uses the stack at
startup and for explicit calls to loader routines, such as dlopen.
NOTE: For PA-32 compatibility mode (with +compat) only: Although it is not a recommended
programming practice, some programs may use stack space "above" the program's current stack.
To preserve the contents "above" the program's logical top of the stack, the dynamic loader attempts
to use stack space far away from program's stack pointer. If a program is doing its own stack
manipulations, such as those implemented by a "threads" package, the dynamic loader may
inadvertently use stack space that the program had reserved for another thread. Programs doing
such stack manipulations must link with archive libraries, or at least use immediate binding and
avoid calling loader routines, if this could potentially cause problems.
Also be aware that if a program sets its stack pointer to memory allocated in the heap, the dynamic
loader may use the space directly "above" the top of this stack.
Version Control
You can maintain multiple versions of a shared library using library-level versioning. This allows
you to make incompatible changes to shared libraries and ensure programs linked with the older
versions continue to run. (See “Library-Level Versioning” (page 111) for more information.)
Debugger Limitations
You can debug shared libraries just like archive libraries with few exceptions. Support is provided
by the WDB Debugger. See the WDB documentation at:
http://www.hp.com/go/wdb
116 Creating and Using Libraries