| United States-English |
|
|
|
![]() |
HP-UX Linker and Libraries User's Guide: HP 9000 Computers > Chapter 5 Creating and Using Libraries Switching from Archive to Shared Libraries |
|
There are cases where a program may behave differently when linked with shared libraries than when linked with archive libraries. These are the result of subtle differences in the algorithms the linker uses to resolve symbols and combine object modules. This section covers these considerations. (See also “Caution When Mixing Shared and Archive Libraries ”.) As discussed previously, in 32-bit mode, ld records the absolute path names of any shared libraries searched at link time in the a.out file. When the program begins execution, the dynamic loader attaches any shared libraries that were specified at link time. Therefore, you must ensure that any libraries specified at link time are also present in the same location at run time. For 64-bit naming, see “Internal Name Processing” for more information. Occasionally, programmers may take advantage of linker behavior that is undocumented but has traditionally worked. With shared libraries, such programming practices might not work or may produce different results. If the old behavior is absolutely necessary, linking with archive libraries only (-a archive) produces the old behavior. For example, suppose several definitions and references of a symbol exist in different object and archive library files. By specifying the files in a particular link order, you could cause the linker to use one definition over another. But doing so requires an understanding of the subtle (and undocumented) symbol resolution rules used by the linker, and these rules are slightly different for shared libraries. So make files or shell scripts that took advantage of such linker behavior prior to the support of shared libraries may not work as expected with shared libraries. More commonly, programmers may take advantage of undocumented linker behavior to minimize the size of routines copied into the a.out files from archive libraries. This is no longer necessary if all libraries are shared. Although it is impossible to characterize the new resolution rules exactly, the following rules always apply:
As a consequence of the second rule, programs that call wrapper libraries may become larger. (A wrapper library is a library that contains alternate versions of C library functions, each of which performs some bookkeeping and then calls the actual C function. For example, each function in the wrapper library might update a counter of how many times the actual C routine is called.) With archive libraries, if the program references only one routine in the wrapper library, then only the 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. 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 will actually be adjacent in virtual memory. Since 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. To load shared libraries, a program must have a copy of the dynamic loader (dld.sl) 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 uses the stack at startup only.
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 when deferred binding of symbols is used. 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 ” for more information.) Shared libraries can be debugged just like archive libraries with few exceptions. For details on debugging shared libraries, refer to the HP/DDE Debugger User's Guide or the HP-UX Symbolic Debugger User's Guide. Some users may use the chroot super-user command when developing and using shared libraries. This affects the path name that the linker stores in the executable file. For example, if you chroot to the directory /users/hyperturbo and develop an application there that uses the shared library libhype.sl in the same directory, ld records the path name of the library as /libhype.sl. If you then exit from the chrooted directory and attempt to run the application, the dynamic loader won't find the shared library because it is actually stored in /users/hyperturbo/libhype.sl, not in /libhype.sl. Conversely, if you move a program that uses shared libraries into a chrooted environment, you must have a copy of the dynamic loader, dld.sl, and all required shared libraries in the correct locations. Profiling with the prof(1) and gprof(1) commands and the monitor library function is only possible on a contiguous chunk of the main program (a.out). Since shared libraries are not contiguous with the main program in virtual memory, they cannot be profiled. You can still profile the main program, though. If profiling of libraries is required, relink the application with the archive version of the library, using the -a archive option. |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|||||||||||||||