Intermediate Update:
The HP-UX March 2001 linker toolset contains new features:
32-bit support for the +init and +fini initializer/finalizer options. See Initializers for Shared Librariesfor more information.
Virtual Environment Support for HP-UX kernel. See for ld(1) for more information.
Improving Performance with Function Symbol Aliasing describes link time function name aliasing to improve performance.
The HP-UX 11i linker toolset contains new features:
32-bit support for the dl*(3C) shared library management routines, dlopen, dlclose, dlsym, and dlerror. See Shared Library Management Routines for more information.
+objdebugonly option. See for ld(1) for more information.
Odump dump utility to display the contents of a 32-bit native code (SOM) object file. See odump(1) for more information.
gprof 32-bit support for profiling shared libraries. The gprof tool is used to produce profile information about an executable. Enhancements in this release enable these tools to work with incomplete executables and shared libraries. Note that you can profile one and only one incomplete executable or shared library at a time. See Profiling Shared Libraries with gprof(1) and gprof(1) for more information.
Using filtered shared libraries (32-bit mode only). 32-bit support for filtered shared libraries.
Incremental Linking. 64-bit support for incremental linking.
The HP-UX 10.20 and 11.x releases contain performance enhancements:
The HP-UX 11.00 linker toolset contains new features:
If you use the 32-bit mode linker toolset, see the following items:
Changes in Future Releases updated in this chapter.
64-bit Mode Linker Toolset Compatibility with De Facto Industry Standards described in this chapter.
64-bit Mode ELF Object File Format described in this chapter.
Dynamic Path Searching for Shared Libraries describes differences in the run time searching of shared libraries.
Shared Library Symbol Binding Semantics describes differences in shared library binding semantics.
New 64-bit mode linker options, symbols, and features, described inNew Features for 64-bit Mode Linking in this chapter.
Unsupported 32-bit mode features, behavior, and linker options, described in 64-bit Mode Link-time Differences and64-bit Mode Run Time Differences in this chapter.
Using Init/Fini Initializers describes the init/fini support for 64-bit mode shared libraries.
The dlopen Shared Library Management Routines describes the dl* family of shared library management routines for 64-bit mode.
BIND_BREADTH_FIRST Modifier describes the flag added to the shl_load routine to modify search behavior.
Changes in Future Releases updated in this chapter.
The following items were added in the HP-UX 10.30 release:
Options to Improve TLB Hit Rates .
The +k linker option (see ld(1)) to remove an executable if the link fails.
The +kchatr option (see chatr(1)) to improve branch prediction on PA-RISC 2.0.
Improving Shared Library Start-Up Time with fastbind .
Online Help for Linker and Libraries described in this chapter.
PA-RISC Changes in Hardware Compatibility described in this chapter.
Linker Compatibility Warnings.
Dynamic Loader Compatibility Warnings.
The +Ostaticprediction linker option described in the ld(1) man page to use with profile-based optimization
In previous releases, the compilers generated PA-RISC 1.0 code on all HP 9000 Series 800 servers and PA-RISC 1.1 code on Series 700 workstations. HP compilers now by default generate PA-RISC 1.1 code on 1.1 systems and 2.0 code on 2.0 systems.
Using the +DAportable compiler option provides compatibility
of code between PA-RISC 1.1 and 2.0 systems. Note that the HP-UX 10.10
release is the last supported release for PA-RISC 1.0 systems, so 1.1 and
2.0 code generated by the HP-UX 10.20 release (or later) of HP compilers
is not supported on PA-RISC 1.0 systems.
| NOTE | The +DA1.0 option will be obsolete in a future release. You cannot build PA1.0 executables on 11.x and run them on 10.x systems. You can achieve better performance on PA-RISC 1.1 and 2.0 systems by not using this option. |
/usr/ccs/bin/ld: (Warning) At least one PA 2.0 object file (sum.o) was detected. The linked output may not run on PA 1.x system.If you try to run a PA-RISC 2.0 program on a 1.1 system, you'll see a message like:
$ a.out ksh: ./a.out: Executable file incompatible with hardwareIn this example, the +DAportable compiler option can be used to create code compatible for PA-RISC 1.1 and 2.0 systems.
See the file /opt/langtools/lib/sched.models for a complete list of model numbers and their architectures. Use the command model to determine the model number of your system.
Dynamic path searching
Library-level versioning
dl* family of dynamic loading routines
Breadth-first symbol searching
ld +compat option for compatibility with 32-bit linking and loading behavior.
The following options instruct the compiler to generate 64-bit ELF object
code.
| Option | Compiler |
|---|---|
| +DA2.0W | C and aC++ |
| +DD64 | C |
See the HP-UX Software Transition Toolkit (STK) at http://www.software.hp.com/STK/
for more information on the structure of ELF object files.
| Symbol | Definition |
|---|---|
| __SYSTEM_ID | Largest architecture revision level used by any compilation unit |
| _FPU_STATUS | Initial value of FPU status register |
| _end or end | Address of first byte following the end of the main program's data segment; identifies the beginning of the heap segment |
| __TLS_SIZE | Size of the Thread Local Storage segment required by the program |
| __text_start | Beginning of the text segment |
| __text_start_f | Beginning of text segment, declared as a function |
| _etext or etext | End of the text segment |
| _etext_f | End of text segment, declared as a function |
| __data_start | Beginning of the data segment |
| _edata or edata | End of initialized data |
| __gp | Global pointer value |
| __init_start | Beginning of the .init section |
| __init_end | End of the .init section |
| __preinit_start | Beginning of the .preinit section |
| __preinit_end | End of the .preinit section |
| __fini_start | Beginning of the .fini section |
| __fini_end | End of the .fini section |
| __unwind_start | Beginning of the unwind table |
| __unwind_end | End of the unwind table |
| NOTE | The linker generates an error if a user application also defines these symbols. |
| Option or Behavior | Description |
|---|---|
| -A name | Specifies incremental loading. 64-bit applications must use shared libraries instead. |
| -C n | Does parameter type checking. This option is unsupported. |
| -S | Generates an initial program loader header file. This option is unsupported. |
| -T | Save data and relocation information in temporary files to reduce virtual memory requirements during linking. This option is unsupported. |
| -q, -Q, -n | Generates an executable with file type DEMAND_MAGIC, EXEC_MAGIC, and SHARE_MAGIC respectively. These options have no effect and are ignored in 64-bit mode. |
| -N | Causes the data segment to be placed immediately after the text segment. This option is accepted but ignored in 64-bit mode. If this option is used because your application data segment is large, then the option is no longer needed in 64-bit mode. If this option is used because your program is used in an embedded system or other specialized application, consider using mapfile support with the -k option. |
| +cg pathname | Specifies pathname for compiling I-SOMs to SOMs. This option is unsupported. |
| +dpv | Displays verbose messages regarding procedures which have been removed due to dead procedure elimination. Use the -v linker option instead. |
| Intra-library versioning | Specified by using the HP_SHLIB_VERSION pragma (C and aC++)
or SHLIB_VERSION directive (Fortran90).
In 32-bit mode, the linker lets you version your library by object files. 64-bit applications must use SVR4 library-level versioning instead. |
| Duplicate code and data symbols | Code and data cannot share the same namespace in 64-bit mode. You should rename the conflicting symbols. |
| All internal and undocumented linker options | These options are unsupported. |
For more information, see the HP-UX Linker and Libraries Online User
Guide (ld +help).
Symbol searching in dependent libraries.
The following table summarizes the dynamic loader differences between
32-bit and 64-bit mode:
| Linker and Loader Functions | 32-bit Mode Behavior | 64-bit Mode Behavior |
|---|---|---|
| +s and +b path_list ordering | Ordering is significant. | Ordering is insignificant by default.
Use +compat to enforce ordering. |
| Symbol searching in dependent libraries | Depth-first search order. | Breadth-first search order.
Use +compat to enforce depth first ordering. |
| Run time path environment variables | No run time environment variables by default.
If +s is specified, then SHLIB_PATH is available. |
LD_LIBRARY_PATH and SHLIB_PATH are available.
Use +noenv or +compat to turn off run-time path environment variables. |
| +b path_list and -L directories interaction | -L directories recorded as absolute paths in executables. | -L directories are not recorded in executables, if
-L
and +b are both used.
To record all the directories in executables, add all directories specified in -L to +b path_list. |
For more information on transition issues, see HP-UX 64-bit Porting
and Transition Guide.
A future release will support the ELF 32 object file format.
Future of ld +compat option
The +compat linker option and support of compatibility mode may be discontinued in a future release.
Support of shl_load shared library management routines
A future release may discontinue support of the shl_load family of shared library management routines.
To access the Linker and Libraries Online User Guide from the ld command line:
ld +help
Looking "inside" a Compiler describes the process of creating an executable file in more detail.
Linking Programs on HP-UX describes how ld creates an executable file from one or more object files.
Linking with Libraries describes conventions for using libraries with ld.
Running the Program describes the process of loading and binding programs at run time.
Linker Thread-Safe Featuresdescribes the thread-safe features.
$ cc -Aa sumnum.cThe compiler displays status, warning, and error messages to standard error output (stderr). If no errors occur, the compiler creates an executable file named a.out in the current working directory. If your PATH environment variable includes the current working directory, you can run a.out as follows:
$ a.out Enter a number: 4 Sum 1 to 4: 10The process is essentially the same for all HP-UX compilers. For instance, to compile and run a similar FORTRAN program named sumnum.f:
$ f77 sumnum.f Compile and link sumnum.f. ... The compiler displays any messages here. $ a.out Run the program. ... Output from the program is displayed here.Program source can also be divided among separate files. For example, sumnum.c could be divided into two files: main.c, containing the main program, and func.c, containing the function sum_n. The command for compiling the two together is:
$ cc -Aa main.c func.c main.c: func.c:Notice that cc displays the name of each source file it compiles. This way, if errors occur, you know where they occur.
#include <stdio.h> /* contains standard I/O defs */
int sum_n( int n ) /* sum numbers from n to 1 */
{
int sum = 0; /* running total; initially 0 */
for (; n >= 1; n--) /* sum from n to 1 */
sum += n; /* add n to sum */
return sum; /* return the value of sum */
}
main() /* begin main program */
{
int n; /* number to input from user */
printf("Enter a number: "); /* prompt for number */
scanf("%d", &n); /* read the number into n */
printf("Sum 1 to %d: %d\\n", n, sum_n(n)); /* display the sum */
}
Generally speaking, the compiler reads one or more source files, one of
which contains a main program, and outputs an executable
a.out
file, as shown in Figure 1: High-Level
View of the Compiler .

Then, the driver calls the HP-UX linker (ld) which builds an a.out file from the object files. This is known as the link-edit phase of compilation. (See Also Compiler-Linker Interaction .)

The C, C++, FORTRAN, and Pascal compilers provide the -v (verbose) option to display the phases a compiler is performing. Compiling main.c and func.c with the -v option produced this output on a Series 700 workstation (\ at the end of a line indicates the line is continued to the next line):
$ cc -Aa -v main.c func.c -lm cc: CCOPTS is not set. main.c: /opt/langtools/lbin/cpp.ansi main.c /var/tmp/ctmAAAa10102 \\ -D__hp9000s700 -D__hp9000s800 -D__hppa -D__hpux \\ -D__unix -D_PA_RISC1_1 cc: Entering Preprocessor. /opt/ansic/lbin/ccom /var/tmp/ctmAAAa10102 main.o -O0 -Aa \\ func.c: /opt/langtools/lbin/cpp.ansi func.c /var/tmp/ctmAAAa10102 \\ -D__hp9000s700 -D__hp9000s800 -D__hppa -D__hpux \\ -D__unix -D_PA_RISC1_1 cc: Entering Preprocessor. /opt/ansic/lbin/ccom /var/tmp/ctmAAAa10102 func.o -O0 -Aa cc: LPATH is /usr/lib/pa1.1:/usr/lib:/opt/langtools/lib: /usr/ccs/bin/ld /opt/langtools/lib/crt0.o -u main main.o func.o \\ -lm -lc cc: Entering Link editor.This example shows that the cc driver calls the C preprocessor (/opt/langtools/lbin/cpp.ansi) for each source file, then calls the actual C compiler (/opt/ansic/lbin/ccom) to create the object files. Finally, the driver calls the linker (/usr/ccs/bin/ld) on the object files created by the compiler (main.o and func.o).
To keep track of where all the symbols and external references occur,
an object file has a symbol table. The linker uses the symbol tables
of all input object files to match up external references to global definitions.
$ cc -Aa -v main.c func.c -lm cc: CCOPTS is not set. main.c: /opt/langtools/lbin/cpp.ansi main.c /var/tmp/ctmAAAa10102 \\ -D__hp9000s700 -D__hp9000s800 -D__hppa -D__hpux \\ -D__unix -D_PA_RISC1_1 cc: Entering Preprocessor. /opt/ansic/lbin/ccom /var/tmp/ctmAAAa10102 main.o -O0 -Aa func.c: /opt/langtools/lbin/cpp.ansi func.c /var/tmp/ctmAAAa10102 \\ -D__hp9000s700 -D__hp9000s800 -D__hppa -D__hpux \\ -D__unix -D_PA_RISC1_1 cc: Entering Preprocessor. /opt/ansic/lbin/ccom /var/tmp/ctmAAAa10102 func.o -O0 -Aa cc: LPATH is /usr/lib/pa1.1:/usr/lib:/opt/langtools/lib: /usr/ccs/bin/ld /opt/langtools/lib/crt0.o -u main main.o func.o -lm -lc cc: Entering Link editor.The next-to-last line in the above example is the command line the compiler used to invoke the 32-bit mode linker, /usr/ccs/bin/ld. In this command, ld combines a startup file (crt0.o) and the two object files created by the compiler (main.o and func.o). Also, ld searches the libm and libc libraries.
In 64-bit mode, the startup functions are handled by the dynamic loader,
dld.sl.
In most cases, the ld command line does not include
crt0.o.
| NOTE | If you are linking any C++ object files to create an executable or a shared library, you must use the CC command to link. This ensures that c++patch executes and chains together your nonlocal static constructors and destructors. If you use ld, the library or executable may not work correctly and you may not get any error messages. For more information see the HP C++ Programmer's Guide. |
In the C program example (see Compiling Programs
on HP-UX: An Example ) main.o contains an external reference
to sum_n, which has a global definition in func.o.
ld
matches the external reference to the global definition, allowing the main
program code in a.out to access sum_n (see Figure
3: Matching the External Reference to sum_n ).

If ld cannot match an external reference to a global definition, it displays a message to standard error output. If, for instance, you compile main.cwithoutfunc.c, ld cannot match the external reference to sum_n and displays this output:
$ cc -Aa main.c /usr/ccs/bin/ld: Unsatisfied symbols: sum_n (code)
The 64-bit linker uses the startup file, /opt/langtools/lib/pa_64/crt0.o, when:
The linker is in default standard mode (+std) with the -noshared option.
If the linker option -I is specified to create an executable file with profile-based optimization, in 32-bit mode icrt0.o is used, and in 64-bit mode the linker inserts /usr/ccs/lib/pa20_64/fdp_init.o. If the linker options -I and -b are specified to create a shared library with profile-based optimization, in 32-bit mode scrt0.o is used, and in 64-bit mode, the linker inserts /usr/ccs/lib/pa20_64/fdp_init_sl.o. In 64-bit mode, the linker uses the single 64-bit crt0.o to support these option.
For details on startup files, see crt0(3).
In 64-bit mode for dynamically bound executables, the entry point, defined
by the symbol $START$ in the dynamic loader (dld.sl).
| To set the magic number to: | Use this option: |
|---|---|
| SHARE_MAGIC | -n |
| DEMAND_MAGIC | -q |
| EXEC_MAGIC | -N |
An executable file's magic number can also be changed using the chatr command (see Changing a Program's Attributes with chatr(1) ). However, chatr can only toggle between SHARE_MAGIC and DEMAND_MAGIC; it cannot be used to change from or to EXEC_MAGIC. This is because the file format of SHARE_MAGIC and DEMAND_MAGIC is exactly the same, while EXEC_MAGIC files have a different format. For details on magic numbers, refer to magic(4).
In 64-bit mode, the linker sets the magic number to the predefined type
for ELF object files (\177ELF). The value of the E_TYPE
in the ELF object file specifies how the file should be loaded.
$ umask 022 $ ls -l a.out -rwxr-xr-x 1 michael users 74440 Apr 4 14:38 a.out
libname.suffix
$ cc -Aa -v main.c func.c ... /usr/ccs/bin/ld /opt/langtools/lib/crt0.o -u main main.o \ func.o -lc cc: Entering Link editor.Similarly, the Series 700/800 FORTRAN compiler automatically links with the libcl (C interface), libisamstub (ISAM file I/O), and libc libraries:
$ f77 -v sumnum.f ... /usr/ccs/bin/ld -x /opt/langtools/lib/crt0.o \ sumnum.o -lcl -lisamstub -lc
| NOTE | If multiple definitions of a symbol occur in the specified libraries, ld does not necessarily choose the first definition. It depends on whether the program is linked with archive libraries, shared libraries, or a combination of both. Depending on link order to resolve such library definition conflicts is risky because it relies on undocumented linker behavior that may change in future releases. (See Also Caution When Mixing Shared and Archive Libraries .) |
Determine where to begin execution of the program - that is, the entry point - usually in crt0.o. (See Also The crt0.o Startup File.)
When the program uses shared libraries, the crt0.o startup code invokes the dynamic loader (dld.sl), which in turn attaches any required shared libraries. If immediate binding was specified at link time, then the libraries are bound immediately. If deferred binding was specified, then libraries are bound as they are referenced. (See Also What are Shared Libraries?.)
The dynamic loader binds only those symbols that are reachable during
the execution of the program. This is similar to how archive libraries
are treated by the linker; namely, ld pulls in an object file
from an archive library only if the object file is needed for program execution.
Also, beginning with the HP-UX 10.30 release, the linker toolset provides thread local storage support in:
dld.sl - the shared library dynamic loader
crt0.o - the program startup file
| NOTE | A program with thread local storage is only supported on systems running HP-UX 10.30 or later versions of the operating system. |
| NOTE | Use of the __thread keyword in a shared library prevents that shared library from being dynamically loaded, that is, loaded by an explicit call to shl_load(). |
See Programming with Threads on HP-UX for information on threads.
As per the libc cumulative patches, PHCO_22923 (11.00) and PHCO_23772 (11.11), t he libc shared library contains stubs for the pthread_* functions in libpthread and libcma. The stubs allow non-threaded applications to dynamically load threa d-safe libraries successfully, so that the pthread symbols are resolved. Applica tions that resolves pthread/cma calls to the stub must be built without -lpthread or -lcma on the link line.
Stubs provided in libc do not have any functionality, these are dummy functions returning zero except pthread_getspecific() family of APIs which has full functi onality implemented in the stubs.
List of pthread calls for which the stubs are provided in the C library is given below.
The pthread calls to any of the above stub returns zero.
The stub for the following pthread calls has full functionality. More informatio n about their functionalities is in the pthread (3T) man pages.
Calls to the stub,
An application may inadvertently pick up the stubs present in libc when it is in tended to use the real pthread APIs, or cma APIs. These are link order problems. An application that needs cma behavior must link to libcma and must do so in th e supported link order, i.e. the link line should only be shared and not contain -lc before -lcma.
So long as this condition is met, the correct cma functions will be referenced. Similarly, a multithreaded application that needs pthread library behavior must link to libpthread and must do so in a supported link order, and only use shared libc and libpthread.
The applications or any library linked that will resolve pthread/cma calls to th e stubs must be built without -lpthread or -lcma on the link line. If you specif y -lc before -lpthread, your application will use the pthread stubs in libc, but other problems may occur as given in the examples below:
$ cat thread.c #include#include void *thread_nothing(void *p) { printf("Success\n"); } int main() { int err; pthread_t thrid; err = pthread_create(&thrid, (pthread_attr_t *) NULL, thread_nothing, (void *) NULL); sleep(1); if (err) { printf("Error\n"); return err; } } $ cc thread.c -lc -lpthread $ a.out Error $ chatr a.out a.out: shared executable shared library dynamic path search: SHLIB_PATH disabled second embedded path disabled first Not Defined shared library list: dynamic /usr/lib/libc.2 <- libc before libpthread dynamic /usr/lib/libpthread.1 shared library binding: deferred global hash table disabled $ cc thread.c -lpthread $ a.out Success $ chatr a.out a.out: shared executable shared library dynamic path search: SHLIB_PATH disabled second embedded path disabled first Not Defined shared library list: dynamic /usr/lib/libpthread.1 dynamic /usr/lib/libc.2 shared library binding: deferred global hash table disabled ...
Specifying -lc before -lpthread in threaded applications can cause run-time prob lems as in the following example. Because the pthread/cma stubs are resolved ins tead of the real pthread/cma functions:
$ cat a.c
#include
#include
extern int errno;
main()
{
shl_load("/usr/lib/librt.2", BIND_DEFERRED, 0);
printf("Error %d, %s\n", errno, strerror(errno));
}
$ cc a.c -lc -lpthread $ a.out Error 22, Invalid argument $ LD_PRELOAD=/usr/lib/libpthread.1 ./a.out Error 0, Error 0
$ cat b.c
#include
#include
void* handle;
extern int errno;
main()
{
handle = dlopen("lib_not_found", RTLD_LAZY);
printf("Error %d, %s\n", errno, strerror(errno));
if (handle == NULL) {
printf("Error: %s\n",dlerror());
}
}
$ cc b.c -lc -lpthread $ a.out Error 22, Invalid argument Error: $ LD_PRELOAD=/usr/lib/libpthread.1 ./a.out Error 0, Error 0 Error: Can't open shared library: lib_not_found
Therefore, -lc should never be specified in the build command of an executable o r shared library.
By default, the compiler drivers (cc, aCC, f90) automatically pass -lc to the li nker at the end of the link line of the executables. It is not necessary to spec ify -lc when building a shared library because libc will be resolved by the refe rence to libc in the executable build command. The libc will be resolved by -lc that is automatically passed by the compiler drivers to the linker.
To see if a shared library was built with -lc, look at the shared library list i n the chatr() output, or list the dependent libraries with ldd(1):
$ cc +z -c lib1.c
$ ld -b -o lib1.sl lib1.o -lc
$ ldd lib1.sl
/usr/lib/libc.2 => /usr/lib/libc.2
/usr/lib/libdld.2 => /usr/lib/libdld.2
/usr/lib/libc.2 => /usr/lib/libc.2
$ cc +DA2.0W +z -c lib1.c
$ ld -b -o lib1.sl lib1.o -lc
$ ldd lib1.sl
libc.2 => /lib/pa20_64/libc.2
libdl.1 => /usr/lib/pa20_64/libdl.1
To see the order in which dependent shared libraries will be loaded at run-time (order is only valid in 64-bit mode), use ldd(1) on the executable (ldd in 32-bi t mode displays the order in which libraries are loaded in reverse order):
$ cc +DA2.0W thread.c -lpthread
$ ldd a.out
libpthread.1 => /usr/lib/pa20_64/libpthread.1
libc.2 => /usr/lib/pa20_64/libc.2
libdl.1 => /usr/lib/pa20_64/libdl.1
$ cc +DA2.0W thread.c -lc -lpthread
$ ldd a.out
libc.2 => /usr/lib/pa20_64/libc.2
libpthread.1 => /usr/lib/pa20_64/libpthread.1
libdl.1 => /usr/lib/pa20_64/libdl.1
$ cc +DA2.0W thread.c -lpthread -lc
$ ldd a.out
libpthread.1 => /usr/lib/pa20_64/libpthread.1
libc.2 => /usr/lib/pa20_64/libc.2
libdl.1 => /usr/lib/pa20_64/libdl.1
If a 64-bit shared library is built with -lpthread but the executable is not, li bc is loaded before libpthread (due to breadth-first searching), and the pthread calls are resolved to the pthread stubs in libc. At run-time, after the a.out i s loaded, the dependencies of a.out are loaded in breadth-first order: libc is loaded as a dependent of a.out before libpthread is loaded as a dependent of libc.2. The dependency list of the first case is:
a.out
/ / \
lib1 lib2 libc
| |
libc libpthread
Therefore the load graph is constructed as:
lib1.sl --> lib2.sl -->libc.2 --> libpthread.1
This is the desired behavior for non-threaded applications, but causes threaded applications (that use either libpthread or libcma) to fail.
# lib1.sl specifies -lc; lib2.sl specifies -lpthread;
no -lpthread on a.out
$ cc -c +z +DA2.0W lib1.c lib2.c
lib1.c:
lib2.c:
$ ld -b -o lib1.sl -lc lib1.o
$ ld -b -o lib2.sl -lpthread lib2.o
$ cc +DA2.0W thread.c -L. -l1 -l2
$ a.out
Error
$ ldd a.out
lib1.sl => ./lib1.sl
lib2.sl => ./lib2.sl
libc.2 => /usr/lib/pa20_64/libc.2
libc.2 => /lib/pa20_64/libc.2
libpthread.1 => /lib/pa20_64/libpthread.1
libdl.1 => /usr/lib/pa20_64/libdl.1
# lib2.sl specifies -lpthread; no -lpthread on a.out
$ ld -b -o lib1.sl lib1.o
$ ld -b -o lib2.sl -lpthread lib2.o
$ cc +DA2.0W thread.c -L. -l1 -l2
$ a.out
Error
$ ldd a.out
lib1.sl => ./lib1.sl
lib2.sl => ./lib2.sl
libc.2 => /usr/lib/pa20_64/libc.2
libpthread.1 => /lib/pa20_64/libpthread.1
libdl.1 => /usr/lib/pa20_64/libdl.1
The same problem will occur if -lcma is listed as a dependent library of a share d library, and you would need to link the executable with -lcma.
For threaded applications, run the executable with LD_PRELOAD set to the libpthr ead library or link the executable with -lpthread:
# use LD_PRELOAD to load libpthread first
$ ld -b -o lib1.sl lib1.o
$ ld -b -o lib2.sl -lpthread lib2.o
$ cc +DA2.0W thread.c -L. -l1 -l2
$ a.out
Error
$ ldd a.out
lib1.sl => ./lib1.sl
lib2.sl => ./lib2.sl
libc.2 => /usr/lib/pa20_64/libc.2
libpthread.1 => /lib/pa20_64/libpthread.1
libdl.1 => /usr/lib/pa20_64/libdl.1
$ LD_PRELOAD="/lib/pa20_64/libpthread.1" a.out
Success
# a.out correctly lists -lpthread for a threaded application
$ ld -b -o lib1.sl lib1.o
$ ld -b -o lib2.sl -lpthread lib2.o
$ cc +DA2.0W thread.c -L. -l1 -l2 -lpthread
$ a.out
Success
$ ldd a.out
lib1.sl => ./lib1.sl
lib2.sl => ./lib2.sl
libpthread.1 => /usr/lib/pa20_64/libpthread.1
libc.2 => /usr/lib/pa20_64/libc.2
libpthread.1 => /lib/pa20_64/libpthread.1
libdl.1 => /usr/lib/pa20_64/libdl.1
If the link line of your shared library contains -lc to explicitly link in libc, remove -lc. Otherwise, shared libraries may be referencing libc.2 while the a.out may reference some older (archived) libc version. Thus the application will actually be using two different versions of libc and possibly mixing code. This may cause compatibility problems. Basically, an application or library should ne ver directly link against libc. All programs need to be linked against libc (which the compiler does automatically), so a shared library will always have the interfaces it needs to execute properly without needing to specify -lc on the link line.
Getting Verbose Output with -v
Passing Linker Options from the Compiler Command with -Wl
Changing the Default Library Search Path with -L and LPATH
Changing the Default Shared Library Binding with -B
Choosing Archive or Shared Libraries with -a
Dynamic Linking with -A and -R
Exporting Symbols from main with -E
Getting Verbose Output with -v
Improving Shared Library Performance with -B symbolic
Moving Libraries after Linking with +b
Moving Libraries After Linking with +s and SHLIB_PATH
Passing Linker Options from the Compiler Command with -Wl
Passing Linker Options in a file with -c
Passing Linker Options with LDOPTS
Specifying Libraries with -l and l:
Stripping Symbol Table Information from the Output File with -s and -x
Linking Shared Libraries with -dynamic
Linking Archived Libraries with -noshared
Controlling Archive Library Loading with +[no]forceload
Flagging Unsatisfied Symbols with +[no]allowunsats
Hiding Symbols from export with +hideallsymbols
Changing Mapfiles with -k and +nodefaultmap
Changing Mapfiles with -k and +nodefaultmap
Ignoring Dynamic Path Environment Variables with +noenvvar
Linking in 64-bit Mode with +std
Linking in 32-bit Mode Style with +compat
Controlling Output from the Unwind Table with +strip wind
The -Llibpath option to ld augments the default
search path; that is, it causes ld to search the specified libpath
before the default places. The C compiler (cc), the C++ compiler
(CC), the POSIX FORTRAN compiler (fort77), and the HP
Fortran 90 compiler (f90) recognize the -L option and
pass it directly to ld. However, the HP FORTRAN compiler (f77)
and Pascal compiler (pc) do not recognize -L; it must
be passed to ld with the -Wl option.
$f77 prog.f -Wl,-L,/usr/local/lib -llocal
(The f77 compiler searches /opt/fortran/lib and /usr/lib as default directories.)
To make the f90 compiler search /usr/local/lib to find a locally developed library named liblocal,, use this command line:
$f90 prog.f90 -L/usr/local/lib -llocal
(The f90 compiler searches /opt/fortran90/lib and /usr/lib as default directories.)
For the C compiler, use this command line:
$ cc -Aa prog.c -L /usr/local/lib -llocalThe LPATH environment variable provides another way to override the default search path. For details, see Changing the Default Library Search Path with -L and LPATH .
$ pc -v prog.p /opt/pascal/lbin/pascomp prog.p prog.o -O0 LPATH = /usr/lib/pa1.1:/usr/lib:/opt/langtools/lib /usr/ccs/bin/ld /opt/langtools/lib/crt0.o -z prog.o -lcl -lm -lc unlink prog.o
-Wl,arg1 [,arg2]...
where each argn is an option or argument passed to the linker.
For example, to make ld use the archive version of a library instead
of the shared, you must specify -a archive on the ld
command line before the library.
$ cc -Aa mathprog.c -Wl,-a,archive,-lm,-a,defaultThe command for telling the linker to use an archive version of libm is:
$ ld /opt/langtools/lib/crt0.o mathprog.o -a archive -lm \ -a default -lc
$ cc -Aa -o sum_num prog.c Compile using -o option. $ sum_num Run the program. Enter a number to sum: 5 The sum of 1 to 5: 15
For example, if a C program calls library routines in the curses library (libcurses), you must specify -lcurses on the cc command line:
$ cc -Aa -v cursesprog.c -lcurses ... /usr/ccs/bin/ld /opt/langtools/lib/crt0.o -u main \ cursesprog.o -lcurses -lc cc: Entering Link editor.
$ f77 -c func.f Produce .o for func.f. $ ls func.o func.o Verify that func.o was created. $ f77 main.f func.o Compile main.f with func.o $ a.out Run it to verify it worked.
| NOTE | Unless otherwise noted, all examples show 32-bit behavior. |
In 64-bit mode, you must include crt0.o on the link line for all fully archive links (ld -noshared) and in compatibility mode (+compat). You do not need to include the crt0.o startup file on the ld command line for shared bound links. In 64-bit mode, the dynamic loader, dld.sl, does some of the startup duties previously done by crt0.o.
See The crt0.o Startup File, and the
crt0(3)
man page for more information.
If set, LPATH should contain a list of colon-separated directory path names ld should search. For example, to include /usr/local/lib in the search path after the default directories, set LPATH as follows:
$ LPATH=/usr/lib:/usr/local/lib Korn and Bourne shell syntax. $ export LPATH
For example, suppose you have a locally developed version of libc, which resides in the directory /usr/local/lib. To make ld find this version of libc before the default libc, use the -L option as follows:
$ ld /opt/langtools/lib/crt0.o prog.o -L /usr/local/lib -lcMultiple -L options can be specified. For example, to search /usr/contrib/lib and /usr/local/lib before the default places:
$ ld /opt/langtools/lib/crt0.o prog.o -L /usr/contrib/lib \ -L /usr/local/lib -lcIf LPATH is set, then the -L option specifies the directories to search before the directories specified in LPATH.
To add $ORIGIN to the environment variables LD_LIBRARY_PATH or SHLIB_PATH, just place $ORIGIN in the value of these environment variables. To add $ORIGIN to the RUNPATH, use the linker options +b or -L. To add $ORIGIN to the path of a shared library in the shared library list, use the linker option +origin.
+origin -lxor
+origin shared_library_name(You can only use the +origin option before the -l option or the name of a shared library.) The option causes the linker to add $ORIGIN before the shared library name in the shared library list and set the DF_ORIGIN flag for the output module. At runtime, the dynamic loader determines the directory of the parent module (object module, shared library, or executable) and replaces $ORIGIN for that directory name. For example,
$ ld main.o +origin libx.sl -L -lc
| NOTE | While the +origin option is available, the recommended way
to specify $origin is in the embedded path with the +b
option. For example,
$ ld main.o -lc +b $ORIGINIf you use +b,\$ORIGIN; the $ORIGIN only affects libraries that are subject to dynamic path lookup; that is, the library shared_library_name is specified with -l or with no embedded / character. If you use +origin shared_library_name, the library will be located using $ORIGIN, which is recorded in the full library name. |
$ ld -B immediate /opt/langtools/lib/crt0.o prog.o -lc -lm
To use nonfatal binding, specify the -B nonfatal option along with the -B immediate option on the linker command line. The order of the options is not important, nor is the placement of the options on the line. For example, the following ld command uses nonfatal immediate binding:
$ ld /opt/langtools/lib/crt0.o prog.o -B nonfatal \ -B immediate -lm -lcNote that the -B nonfatal modifier does not work with deferred binding because a symbol must have been bound by the time a program actually references or calls it. A program attempting to call or access a nonexistent symbol is a fatal error.
The -B nonfatal modifier alters this behavior slightly: If the dynamic loader cannot find a symbol in the restricted set, it looks in the global symbol set (the symbols defined in all libraries) to resolve the symbol. If it still cannot find the symbol, then a run-time symbol-binding error occurs and the program aborts.
When is -B restricted most useful? Consider a program that creates duplicate symbol definitions by either of these methods:
The program calls shl_definesym to define a symbol that is already defined in a library that was loaded at program startup.
But what happens when, to take advantage of the performance benefits
of deferred binding, the same program is linked with -B deferred?
If a duplicate, more visible symbol definition is created prior
to referencing the symbol, it binds to the more visible definition, and
the program might run incorrectly. In such cases, -B restricted
is useful, because symbols bind the same way as they do with -B immediate,
but actual binding is still deferred.
A benefit of -B symbolic is that it can help improve application
performance and the resulting shared library will be slightly smaller.
The -B symbolic option is useful for applications that make a
lot of calls between procedures inside a shared library and when
these same procedures are called by programs outside of the shared library.
| NOTE | The -B symbolic option applies only to function, but not variable, references in a shared library. |
$ ld -B symbolic -b func1.o func2.o -o lib1.sl
| NOTE | The +e option overrides the -B symbolic option. For
example, you use +esymbol, only symbol is exported
and all other symbols are hidden. Similarly, if you use +eesymbol,
only symbol is exported, but other symbols exported by default remain
visible.
Since all internal calls inside the shared library are resolved inside the shared library, user-supplied modules with the same name are not seen by routines inside the library. For example, you could not replace internal libc.sl malloc() calls with your own version of malloc() if libc.sl was linked with -B symbolic. |
$ ld -B symbolic -b convert.o volume.o -o libunits.slTwo main programs link to the shared library. main1 calls convert_rtn() and main2 calls gal_to_liter().
$ cc -Aa main1.c libunits.sl -o main1 $ cc -Aa main1.c libunits.sl -o main2

For example, you could hide the gal_to_liter symbol as shown:
$ ld -b convert.o -h gal_to_liter volume.o -o libunits.slor export the convert_rtn symbol:
$ ld -b +e convert_rtn convert.o volume.o -o libunits.slIn both cases, main2 will not be able to resolve its reference to gal_to_liter() because only the convert_rtn() symbol is exported as shown below inFigure 5: Symbol hidden in a Shared Library:

As an example, suppose you write an application that will run on a system
on which shared libraries may not be present. Since the program could not
run without the shared library, it would be best to link with the archive
library, resulting in executable code that contains the required library
routines. See also Caution When Mixing
Shared and Archive Libraries .
-a {archive | shared | default | archive_shared | shared_archive}
The different option settings are:
| CAUTION | You should avoid mixing shared libraries and archive libraries in the same application. For more information see Caution When Mixing Shared and Archive Libraries . |
$ ld /opt/langtools/lib/crt0.o prog.o -a archive -lcurses -lm -lc
However, be aware that dynamic linking is incompatible with shared libraries.
That is, a running program cannot be linked to shared libraries
and also use ld -A to dynamically load object modules.
| NOTE | Another reason to use shared library management routines instead of dynamic linking is that dynamic linking may not be supported in a future release. See Linker Compatibility Warnings and Changes in Future Releasesfor additional future changes. |
Topics in this section include:
An Example Program provides an example dynamic linking scenario.
Allocate the required memory and obtain its starting address.
Link the module from the running application.
Get information about the module's text, data, and bss segments from the module's header.
Read the text and data into the allocated space.
Clear (fill with zeros) the bss segment.
Flush the text from the data cache before executing code from the loaded module.
Get the addresses of routines and data that are referenced in the module.
The useful members of the som_exec_auxhdr structure are:
The location of the text and data segments in the file is defined by
the .exec_tfile and .exec_dfile members of the som_exec_auxhdr
structure. The address at which to place the segments in the allocated
memory is defined by the .exec_tmem and .exec_dmem members.
The size of the segments to read in is defined by the .exec_tsize
and .exec_dsize members.
The end of the data segment can be determined by adding the
.exec_dmem
and
.exec_dsize members of the som_exec_auxhdr structure.
The bss's size is defined by the .exec_bsize member.
Use an assembly language routine named flush_cache (see The
flush_cache Function in this chapter). You must assemble this routine
separately (with the as command) and link it with the main program.
If the module contains multiple routines and data that must be accessed from the main program, the main program can use the nlist(3C) function to get their addresses.
Another approach that can be used is to have the entry point routine
return the addresses of required routines and data.
The program allocates space for dynobj.o by calling a function named alloc_load_space (see The alloc_load_space Function later in this chapter). The program then calls a function named dyn_load to dynamically link and load dynobj.o (see The dyn_load Function later in this chapter). Both functions are defined in a file called dynload.c (see dynload.c ).
As a return value, dyn_load provides the address of the entry point in dynobj.o - in this case, the function foo. To get the addresses of the function bar and the variable counter, the program uses the nlist(3C) function.
Source for dynprog shows the C source code for the dynprog program.
Output of dynprog shows the run time output of the dynprog program.
The flush_cache Function provides example source code in assembly language to flush text from the data cache.
CFLAGS = -Aa -D_POSIX_SOURCE dynprog: dynprog.o dynload.o flush_cache.o # Compile line: cc -o dynprog dynprog.o dynload.o flush_cache.o -Wl,-a,archive file1.o: file1.c dynprog.c file2.o: file2.c # Create flush_cache.o: flush_cache.o: as flush_cache.sThis makefile assumes that the following files are found in the current directory:
$ make dynprog file1.o file2.o cc -Aa -D_POSIX_SOURCE -c dynprog.c cc -Aa -D_POSIX_SOURCE -c dynload.c cc -o dynprog dynprog.o dynload.o -Wl,-a,archive cc -Aa -D_POSIX_SOURCE -c file1.c cc -Aa -D_POSIX_SOURCE -c file2.c as -o flush_cache flush_cache.sNote that the line CFLAGS = causes any C files to be compiled in ANSI mode (-Aa) and causes the compiler to search for routines that are defined in the Posix standard (-D_POSIX_SOURCE).
For details on using make refer to make(1).
#include <stdio.h>
#include <nlist.h>
extern void * alloc_load_space(const char * base_prog,
const char * obj_files,
const char * dest_file);
extern void * dyn_load(const char * base_prog,
unsigned int addr,
const char * obj_files,
const char * dest_file,
const char * entry_pt);
const char * base_prog = "dynprog"; /* this executable's name */
const char * obj_files = "file1.o file2.o"; /* .o files to combine */
const char * dest_file = "dynobj.o"; /* .o file to load */
const char * entry_pt = "foo"; /* define entry pt name */
void glorp (const char *); /* prototype for local function */
void (* foo_ptr) (); /* pointer to entry point foo */
void (* bar_ptr) (); /* pointer to function bar */
int * counter_ptr; /* pointer to variable counter [file2.c] */
main()
{
unsigned int addr; /* address at which to load dynobj.o */
struct nlist nl[3]; /* nlist struct to retrieve addresse */
/*
STEP 1: Allocate space for module:
*/
addr = (unsigned int) alloc_load_space(base_prog,
obj_files, dest_file);
/*
STEP 2: Load the file at the address, and get address of entry point:
*/
foo_ptr = (void (*)()) dyn_load(base_prog, addr, obj_files,
dest_file, entry_pt);
/*
STEP 3: Get the addresses of all desired routines using nlist(3C):
*/
nl[0].n_name = "bar";
nl[1].n_name = "counter";
nl[2].n_name = NULL;
if (nlist(dest_file, nl)) {
fprintf(stderr, "error obtaining namelist for %s\n", dest_file);
exit(1);
}
/*
* Assign the addresses to meaningful variable names:
*/
bar_ptr = (void (*)()) nl[0].n_value;
counter_ptr = (int *) nl[1].n_value;
/*
* Now you can call the routines and modify the variables:
*/
glorp("main");
(*foo_ptr) ();
(*bar_ptr) ();
(*counter_ptr) ++;
printf("counter = %d\n", *counter_ptr);
}
void glorp(const char * from)
{
printf("glorp called from %s\n", from);
}
/****************************************************************
* file1.c - Contains routines foo() and bar().
****************************************************************/
extern int * counter_ptr; /* defined in dynprog.c */
extern int counter; /* defined in file2.c */
extern void glorp(const char * from); /* defined in dynprog.c */
void foo()
{
glorp("foo");
(*counter_ptr) ++; /* update counter indirectly with global pointer */
}
void bar()
{
glorp("bar");
counter ++; /* update counter directly */
}
/****************************************************************
* file2.c - Global counter variable referenced by dynprog.c
* and file1.c.
****************************************************************/
int counter = 0;
glorp called from main glorp called from foo glorp called from bar counter = 3
#include <stdio.h> #include <stdlib.h> #include <nlist.h> # include <filehdr.h> # include <aouthdr.h> # define PAGE_SIZE 4096 /* memory page size */
void * alloc_load_space(const char * base_prog, const char * obj_files, const char * dest_file)
The alloc_load_space function allocates only the required amount of space. To determine how much memory is required, alloc_load_space performs these steps:
Get text, data, and bss segment location and size information to determine how much space to allocate.
Return a pointer to the space. (The address of the space is adjusted to begin on a memory page boundary - that is, a 4096-byte boundary.)
void * alloc_load_space(const char * base_prog,
const char * obj_files,
const char * dest_file)
{
char cmd_buf[256]; /* linker command line */
int ret_val; /* value returned by various lib calls */
size_t space; /* size of space to allocate for module */
size_t addr; /* address of allocated space */
size_t bss_size; /* size of bss (uninitialized data) */
FILE * destfp; /* file pointer for dest_file */
struct som_exec_auxhdr aux_hdr; /* file header */
unsigned int tdb_size; /* size of text, data, and bss combined */
/* ---------------------------------------------------------------
* STEP 1: Pre-link the destination module so we can get its size:
*/
sprintf(cmd_buf, "/bin/ld -a archive -R80000 -A %s -N %s -o %s -lc",
base_prog, obj_files, dest_file);
if (ret_val = system(cmd_buf)) {
fprintf(stderr, "link failed: %s\n", cmd_buf);
exit(ret_val);
}
/* ---------------------------------------------------------------
* STEP 2: Get the size of the module's text, data, and bss segments
* from the auxiliary header for dest_file; add them together to
* determine size:
*/
if ((destfp = fopen(dest_file, "r")) == NULL) {
fprintf(stderr, "error opening %s\n", dest_file);
exit(1);
}
/*
* Must seek past SOM "header" to get to the desired
* "som_exec_auxhdr":
*/
if (fseek(destfp, sizeof(struct header), 0)) {
fprintf(stderr, "error seeking past header in %s\n", dest_file);
exit(1);
}
if (fread(&aux_hdr, sizeof(aux_hdr), 1, destfp) <= 0) {
fprintf(stderr, "error reading som aux header from %s\n", dest_file);
exit(1);
}
/* allow for page-alignment of data segment */
space = aux_hdr.exec_tsize + aux_hdr.exec_dsize
+ aux_hdr.exec_bsize + 2 * PAGE_SIZE;
fclose(destfp); /* done reading from module file */
/* ---------------------------------------------------------------
* STEP 3: Call malloc(3C) to allocate the required memory and get
* its address; then return a pointer to the space:
*/
addr = (size_t) malloc(space);
/*
* Make sure allocated area is on page-aligned address:
*/
if (addr % PAGE_SIZE != 0) addr += PAGE_SIZE - (addr % PAGE_SIZE);
return((void *) addr);
}
void * dyn_load(const char * base_prog, unsigned int addr, const char * obj_files, const char * dest_file, const char * entry_pt)The base_prog, obj_files, and dest_file parameters are the same parameters supplied to alloc_load_space. The addr parameter is the address returned by alloc_load_space, and the entry_pt parameter specifies a symbol name that you want to act as the entry point in the module.
To dynamically link and load dest_file into base_prog, the dyn_load function performs these steps:
Open dest_file and get its header information on the text, data, and bss segments. Read this information into a som_exec_auxhdr structure, which starts immediately after a header structure.
Read the text and data segments into the area allocated by alloc_load_space. (The text and data segments are read separately.)
Initialize (fill with zeros) the bss, which starts immediately after the data segment.
Flush text from the data cache before execution, using the flush_cache routine. (See The flush_cache Function later in this chapter.)
Return a pointer to the entry point, specified by the -e option in Step 1.
void * dyn_load(const char * base_prog,
unsigned int addr,
const char * obj_files,
const char * dest_file,
const char * entry_pt)
{
char cmd_buf[256]; /* buffer holding linker command */
int ret_val; /* holds return value of library calls */
FILE * destfp; /* file pointer for destination file */
unsigned int bss_start; /* start address of bss in VM */
unsigned int bss_size; /* size of bss */
unsigned int entry_pt_addr; /* address of entry point */
struct som_exec_auxhdr aux_hdr; /* som file auxiliary header */
unsigned int tdb_size; /* size of text, data, and bss combined*/
/* -----------------------------------------------------------------
* STEP 1: Dynamically link the module to be loaded:
*/
sprintf(cmd_buf,
"/bin/ld -a archive -A %s -R %x -N %s -o %s -lc -e %s",
base_prog, addr, obj_files, dest_file, entry_pt);
if (ret_val = system(cmd_buf))
{
fprintf(stderr, "link command failed: %s\n", cmd_buf);
exit(ret_val);
}
/* -----------------------------------------------------------------
* STEP 2: Open dest_file. Read its auxiliary header for text, data,
* and bss info:
*/
if ((destfp = fopen(dest_file, "r")) == NULL)
{
fprintf(stderr, "error opening %s for loading\n", dest_file);
exit(1);
}
/*
* Get auxiliary header information from "som_exec_auxhdr" struct,
* which is after SOM header.
*/
if (fseek(destfp, sizeof(struct header), 0))
{
fprintf(stderr, "error seeking past header in %s\n", dest_file);
exit(1);
}
if (fread(&aux_hdr, sizeof(aux_hdr), 1, destfp) <= 0)
{
fprintf(stderr, "error reading som aux header from %s\n", dest_file);
exit(1);
}
/* -----------------------------------------------------------------
* STEP 3: Read the text and data segments into the buffer area:
*/
/*
* Read text and data separately. First load the text:
*/
if (fseek(destfp, aux_hdr.exec_tfile, 0))
{
fprintf(stderr, "error seeking start of text in %s\n", dest_file);
exit(1);
}
if ((fread(aux_hdr.exec_tmem, aux_hdr.exec_tsize, 1, destfp)) <= 0)
{
fprintf(stderr, "error reading text from %s\n", dest_file);
exit(1);
}
/*
* Now load the data, if any:
*/
if (aux_hdr.exec_dsize) {
if (fseek(destfp, aux_hdr.exec_dfile, 0))
{
fprintf(stderr, "error seeking start of data in %s\n", dest_file);
exit(1);
}
if ((fread(aux_hdr.exec_dmem, aux_hdr.exec_dsize, 1, destfp))<= 0)
{
fprintf(stderr, "error reading data from %s\n", dest_file);
exit(1);
}
}
fclose(destfp); /* done reading from module file */
/* -----------------------------------------------------------------
* STEP 4: Zero out the bss (uninitialized data segment):
*/
bss_start = aux_hdr.exec_dmem + aux_hdr.exec_dsize;
bss_size = aux_hdr.exec_bsize;
memset(bss_start, 0, bss_size);
/* -----------------------------------------------------------------
* STEP 5: Flush the text from the data cache before execution:
*/
/*
* The flush_cache routine must know the exact size of the
* text, data, and bss, computed as follows:
* Size = (Data Addr - Text Addr) + Data Size + BSS Size
* where (Data Addr - Text Addr) = Text Size + alignment between
* Text and Data.
*/
tdb_size = (aux_hdr.exec_dmem - aux_hdr.exec_tmem) +
aux_hdr.exec_dsize + aux_hdr.exec_bsize;
flush_cache(addr, tdb_size);
/* -----------------------------------------------------------------
* STEP 6: Return a pointer to the entry point specified by -e:
*/
entry_pt_addr = (unsigned int) aux_hdr.exec_entry;
return ((void *) entry_pt_addr);
}
; flush_cache.s ; ; Routine to flush and synchronize data and instruction caches ; for dynamic loading ; ; Copyright Hewlett-Packard Co. 1985,1991, 1995 ; ; All HP VARs and HP customers have a non-exclusive royalty-free ; license to copy and use this flush_cashe() routine in source ; code and/or object code. .code ; flush_cache(addr, len) - executes FDC and FIC instructions for ; every cache line in the text region given by starting addr and ; len. When done, it executes a SYNC instruction and then enough ; NOPs to assure the cache has been flushed. ; ; Assumption: Cache line size is at least 16 bytes. Seven NOPs ; is enough to assure cache has been flushed. This routine is ; called to flush the cache for just-loaded dynamically linked ; code which will be executed from SR5 (data) space. ; %arg0=GR26, %arg1=GR25, %arg2=GR24, %arg3=GR23, %sr0=SR0. ; loop1 flushes data cache. arg0 holds address. arg1 holds offset. ; SR=0 means that SID of data area is used for fdc. ; loop2 flushes inst cache. arg2 holds address. arg3 holds offset. ; SR=sr0 means that SID of data area is used for fic. ; fdc x(0,y) -> 0 means use SID of data area. ; fic x(%sr0,y) -> SR0 means use SR0 SID (which is set to data area). .proc .callinfo .export flush_cache,entry flush_cache .enter ldsid (0,%arg0),%r1 ; Extract SID (SR5) from address mtsp %r1,%sr0 ; SID -> SR0 ldo -1(%arg1),%arg1 ; offset = length -1 copy %arg0,%arg2 ; Copy address from GR26 to GR24 copy %arg1,%arg3 ; Copy offset from GR25 to GR23 fdc %arg1(0,%arg0) ; Flush data cache @SID.address+offset l