Sun Microsystems, Inc.
spacer |
black dot
2.  Link-Editor Input File Processing Archive Processing  Previous   Contents   Next 

Shared Object Processing

Shared objects are indivisible whole units that have been generated by a previous link-edit of one or more input files. When the link-editor processes a shared object, the entire contents of the shared object become a logical part of the resulting output file image. This logical inclusion means that all symbol entries defined in the shared object are made available to the link-editing process. The shared object is actually copied during process execution.

The shared object's program data sections and most of the link-editing information sections are unused by the link-editor. These sections are interpreted by the runtime linker when the shared object is bound to generate a runnable process. However, the occurrence of a shared object is remembered, and information is stored in the output file image to indicate that this object is a dependency and must be made available at runtime.

By default, all shared objects specified as part of a link-edit are recorded as dependencies in the object being built. This recording is made regardless of whether the object being built actually references symbols offered by the shared object. To minimize runtime linking overhead, specify only those dependencies required to resolve symbol references from the object being built as part of the link-edit. The link-editor's debugging capabilities, and ldd(1) with the -u option, can be used to determine unused dependencies. Alternatively, the link-editor's -z ignore option can suppress the dependency recording of unused shared objects.

If a shared object has dependencies on other shared objects, these too will be processed. This processing occurs after all command-line input files have been processed. These shared objects will be used to complete the symbol resolution process; however, their names will not be recorded as dependencies in the output file image being generated.

Although the position of a shared object on the link-edit command-line has less significance than it does for archive processing, the position can have a global effect. Multiple symbols of the same name are allowed to occur between relocatable objects and shared objects, and between multiple shared objects. See "Symbol Resolution".

The order of shared objects processed by the link-editor is maintained in the dependency information stored in the output file image. As the runtime linker reads this information, it loads the specified shared objects in the same order. Therefore, the link-editor and the runtime linker select the first occurrence of a symbol of a multiply-defined series of symbols.

Note - Multiple symbol definitions, and thus the information to describe the interposing of one definition of a symbol for another, are reported in the load map output generated using the -m option.

Linking With Additional Libraries

Although the compiler drivers often ensure that appropriate libraries are specified to the link-editor, frequently you must supply your own. Shared objects and archives can be specified by explicitly naming the input files required to the link-editor, but a more common and more flexible method involves using the link-editor's -l option.

Library Naming Conventions

By convention, shared objects are usually designated by the prefix lib and the suffix .so, and archives are designated by the prefix lib and the suffix .a. For example, is the shared object version of the standard C library made available to the compilation environment, and libc.a is the library's archive version.

These conventions are recognized by the -l option of the link-editor. This option is commonly used to supply additional libraries to a link-edit. The following example directs the link-editor to search for If the link-editor does not find, it searches for libfoo.a before moving on to the next directory to be searched.

$ cc -o prog file1.c file2.c -lfoo

Note - There is a naming convention regarding the compilation environment and the runtime environment use of shared objects. The compilation environment uses the simple .so suffix, whereas the runtime environment commonly uses the suffix with an additional version number. See "Naming Conventions" and "Coordination of Versioned Filenames".

When link-editing in dynamic mode, you can choose to link with a mix of shared objects and archives. When link-editing in static mode, only archive libraries are acceptable for input.

When in dynamic mode and using the -l option to enable a library search, the link-editor will first search in a given directory for a shared object that matches the specified name. If no match is found, the link-editor will then look for an archive library in the same directory. When in static mode and using the -l option, only archive libraries will be sought.

Linking With a Mix of Shared Objects and Archives

The library search mechanism in dynamic mode searches a given directory for a shared object, and then searches an archive library. Finer control of the type of search required is possible through the -B option.

By specifying the -B dynamic and -B static options on the command line as many times as required, you can toggle the library search between shared objects or archives respectively. For example, to link an application with the archive libfoo.a and the shared object, issue the following command:

$ cc -o prog main.o file1.c -Bstatic -lfoo -Bdynamic -lbar

The -B static and -B dynamic keywords are not exactly symmetrical. When you specify -B static, the link-editor does not accept shared objects as input until the next occurrence of -B dynamic. However, when you specify -B dynamic, the link-editor first looks for shared objects and then archive library's in any given directory.

The precise description of the previous example is that the link-editor first searches for libfoo.a, and then for, and if that fails, for libbar.a. Finally, it will search for, and if that fails, libc.a.

Position of an Archive on the Command Line

The position of an archive on the command line can affect the output file being produced. The link-editor searches an archive only to resolve undefined or tentative external references it has previously seen. After this search is completed and any required members have been extracted, the link-editor moves onto the next input file on the command line.

Therefore by default, the archive is not available to resolve any new references from the input files that follow the archive on the command line. For example, the following command directs the link-editor to search libfoo.a only to resolve symbol references that have been obtained from file1.c. The libfoo.a archive is not available to resolve symbol references from file2.c or file3.c.

$ cc -o prog file1.c -Bstatic -lfoo file2.c file3.c -Bdynamic

Note - You should specify any archives at the end of the command line unless multiple-definition conflicts require you to do otherwise.

In some instances users have interdependencies between archives such that the extraction of members from one archive is resolved by extracting members from another archive. If these dependencies are cyclic, the archives must be specified repeatedly on the command line to satisfy previous references. For example:

$ cc -o prog .... -lA -lB -lC -lA -lB -lC -lA

The determination, and maintenance, of repeated archive specifications can be tedious. The -z rescan option makes this process simpler. Following all input file processing, this option causes the entire archive list to be reprocessed in an attempt to locate additional archive members that resolve symbol references. This archive rescanning continues until a pass over the archive list occurs in which no new members are extracted. The previous example could therefore be simplified to:

$ cc -o prog -z rescan .... -lA -lB -lC

Directories Searched by the Link-Editor

All previous examples assume the link-editor knows where to search for the libraries listed on the command line. By default, when linking 32-bit objects, the link-editor knows of only two standard directories in which to look for libraries, /usr/ccs/lib and /usr/lib. When linking 64-bit objects, only one standard directory is used, /usr/lib/64. All other directories to be searched must be added to the link-editor's search path explicitly.

You can change the link-editor search path in two ways: using a command-line option, or using an environment variable.

Using a Command-Line Option

You can use the -L option to add a new path name to the library search path. This option affects the search path at the point it is encountered on the command line. For example, the following command searches path1, then /usr/ccs/lib and /usr/lib, to find libfoo. It searches path1 and then path2, and then /usr/ccs/lib and /usr/lib, to find libbar.

$ cc -o prog main.o -Lpath1 file1.c -lfoo file2.c -Lpath2 -lbar

Path names defined using the -L option are used only by the link-editor. These path names are not recorded in the output file image created for use by the runtime linker.

Note - You must specify -L if you want the link-editor to search for libraries in your current directory. You can use a period (.) to represent the current directory.

You can use the -Y option to change the default directories searched by the link-editor. The argument supplied with this option takes the form of a colon separated list of directories. For example, the following command searches for libfoo only in the directories /opt/COMPILER/lib and /home/me/lib.

$ cc -o prog main.c -YP,/opt/COMPILER/lib:/home/me/lib -lfoo

The directories specified using the -Y option can be supplemented by using the -L option.

Using an Environment Variable

You can also use the environment variable LD_LIBRARY_PATH, which takes a colon-separated list of directories, to add to the link-editor's library search path. In its most general form, LD_LIBRARY_PATH takes two directory lists separated by a semicolon. The first list is searched before the lists supplied on the command line, and the second list is searched after.

The following example shows the combined effect of setting LD_LIBRARY_PATH and calling the link-editor with several -L occurrences:

$ LD_LIBRARY_PATH=dir1:dir2;dir3
$ cc -o prog main.c -Lpath1 ... -Lpath2 ... -Lpathn -lfoo

The effective search path will be dir1:dir2:path1:path2... pathn:dir3:/usr/ccs/lib:/usr/lib.

If no semicolon is specified as part of the LD_LIBRARY_PATH definition, the specified directory list is interpreted after any -L options. In the following example the effective search path will be path1:path2... pathn:dir1:dir2:/usr/ccs/lib:/usr/lib.

$ LD_LIBRARY_PATH=dir1:dir2
$ cc -o prog main.c -Lpath1 ... -Lpath2 ... -Lpathn -lfoo

Note - This environment variable can also be used to augment the search path of the runtime linker. See "Directories Searched by the Runtime Linker". To prevent this environment variable from influencing the link-editor, use the -i option.

Directories Searched by the Runtime Linker

By default, the runtime linker knows of only one standard place to look for libraries, /usr/lib when processing 32-bit objects, and /usr/lib/64 when processing 64-bit objects. All other directories to be searched must be added to the runtime linker's search path explicitly.

When a dynamic executable or shared object is linked with additional shared objects, these shared objects are recorded as dependencies that must be located again during process execution by the runtime linker. During the link-edit, one or more search paths can be recorded in the output file. These search paths are used by the runtime linker to locate any shared object dependencies. These recorded search paths are referred to as a runpath.

Objects may be built with the -z nodefaultlib option to suppress any search of the default locations at runtime. Use of this option implies that all the dependencies of an object can be located using its runpaths. Without this option, which is the most common case, no matter how you augment the runtime linker's library search path, its last element is always /usr/lib for 32-bit objects and /usr/lib/64 for 64-bit objects.

Note - Default search paths can be administrated using a runtime configuration file. See "Configuring the Default Search Paths". However the creator of an object should not rely on the existence of this file, and should always ensure that their object can locate its dependencies with only its runpaths or standard system defaults.

You can use the -R option, which takes a colon-separated list of directories, to record a runpath in a dynamic executable or shared object. The following example will record the runpath /home/me/lib:/home/you/lib in the dynamic executable prog.

$ cc -o prog main.c -R/home/me/lib:/home/you/lib -Lpath1 \
-Lpath2 file1.c file2.c -lfoo -lbar

The runtime linker uses these paths, then the default location /usr/lib, to locate any shared object dependencies. In this case, this runpath is used to locate and

The link-editor accepts multiple -R options and concatenates each of these specifications, separated by a colon. Thus, the previous example can also be expressed as:

$ cc -o prog main.c -R/home/me/lib -Lpath1 -R/home/you/lib \
-Lpath2 file1.c file2.c -lfoo -lbar

For objects that may be installed in various locations, the $ORIGIN dynamic string token provides a flexible means of recording a runpath. See "Locating Associated Dependencies".

Note - A historic alternative to specifying the -R option is to set the environment variable LD_RUN_PATH, and make this available to the link-editor. The scope and function of LD_RUN_PATH and -R are identical, but when both are specified, -R supersedes LD_RUN_PATH.

Initialization and Termination Sections

Dynamic objects may supply code that provides for runtime initialization and termination processing. This code can be encapsulated in one of two ways, either an array of function pointers or a single code block. Each of these section types is built from a concatenation of like sections from the input relocatable objects.

The sections .preinit_array, .init_array and .fini_array provide arrays of, respectively, runtime pre-initialization, initialization, and termination functions. When creating a dynamic object, the link-editor identifies these arrays with the .dynamic tags DT_PREINIT_ARRAY and DT_PREINIT_ARRAYSZ, DT_INIT_ARRAY and DT_INIT_ARRAYSZ, and DT_FINI_ARRAY and DT_FINI_ARRAYSZ accordingly, so that they may be called by the runtime linker. The pre-initialization array is applicable to dynamic executables only. See "Initialization and Termination Routines".

The sections .init and .fini provide, respectively, a runtime initialization and termination code block. However, the compiler drivers typically supply .init and .fini sections as part of the files they add to the beginning and end of your input file list. These files have the effect of encapsulating the .init and .fini code into individual functions that are identified by the reserved symbol names _init and _fini respectively. When creating a dynamic object, the link-editor identifies these symbols with the .dynamic tags DT_INIT and DT_FINI accordingly, so that they may be called by the runtime linker. See "Initialization and Termination Routines".

The registration of initialization and termination functions can be carried out directly by the link-editor using the -z initarray and -z finiarray options. For example, the following command results in the address of the function foo being placed in an .initarray element, and the address of the function bar being placed in a .finiarray element.

$ cat main.c
#include    <stdio.h>

void foo()
        (void) printf("initializing: foo()\n");

void bar()
        (void) printf("finalizing: bar()\n");

        (void) printf("main()\n");
        return (0);

$ cc -o main -zinitarray=foo -zfiniarray=bar main.c
$ main
initializing: foo()
finalizing: bar()
  Previous   Contents   Next