On AIX, symbol resolution is performed at link-time and cannot be rebound at the program load-time, except for the two exceptions explained in the following sections:
This means that once an executable file was generated, dependent shared objects and archive members in libraries must be referenced using the same path name all the time; otherwise, the executable cannot run.
However, this does not necessary mean that dependent shared objects and archive members in libraries must be in the same directory all the time. If no path information is associated those objects and members, the system loader will look for them in several directories specified by the -L linker option (see 2.3.1, “The -L linker option” on page 55) and the LIBPATH environment variable (see 2.3.3, “LIBPATH environment variable” on page 58), in addition to the default library search directories, /usr/lib and /lib.
This mechanism simplifies the work of the system loader when a module is loaded, and thus results in better execution performance, though it could be seen rigid and tedious from the application programmers’ view.
To demonstrate this behavior, we have copied libc.a to /tmp and build an executable file from the program shown in Example 2-1 on page 43 as follows:
$ cp /usr/lib/libc.a /tmp
$ ls -l /tmp/libc.a
-r-x------ 1 k5 k5 6793964 Apr 18 15:35 /tmp/libc.a
$ chmod a+r /tmp/libc.a
$ ls -l /tmp/libc.a
-r-xr--r-- 1 k5 k5 6793964 Apr 18 15:35 /tmp/libc.a
$ cc helloworld.c /tmp/libc.a
Note
Shared objects or libraries must be readable from other users; otherwise they are treated as private shared objects (see 2.9.2, “Private shared objects” on page 101 for more detail).
The executable file cannot run if /tmp/libc.a is removed as follows:
$ ./a.out Hello World $ rm -i /tmp/libc.a rm: Remove /tmp/libc.a? y $ ./a.out exec(): 0509-036 Cannot load program ./a.out because of the following errors: 0509-150 Dependent module /tmp/libc.a(shr.o) could not be loaded. 0509-022 Cannot load module /tmp/libc.a(shr.o). 0509-026 System error: A file or directory in the path name does not exist.
The reason is that the reference information to the removed /tmp/libc.a file was statically stored in the XCOFF header of the executable file, as emphasized in Example 2-5 on page 55.
The directory path names, except for the first (index 0) section, shown in the PATH column are called optional path components for dependent modules. In Example 2-5 on page 55, libc.a has the optional path component /tmp.
$ dump -H a.out
a.out:
***Loader Section***
Loader Header Information
VERSION# #SYMtableENT #RELOCent LENidSTR
0x00000001 0x00000007 0x00000010 0x00000031
#IMPfilID OFFidSTR LENstrTBL OFFstrTBL
0x00000002 0x00000188 0x0000002a 0x000001b9
***Import File Strings***
INDEX PATH BASE MEMBER
0 /usr/lpp/xlopt:/usr/lib:/lib
1 /tmp libc.a shr.o
|
Note
It is always recommended to avoid having any optional path components when creating shared objects and libraries and building executable files, in order to avoid unnecessary dependency to the file path names of the dependent modules.
If the same program is built as follows:
$ cc helloworld.c
the XCOFF header will not contain any path name information for libc.a as highlighted in the following (the compiler driver automatically add -lc before invoking the linker in this case):
***Import File Strings***
INDEX PATH BASE MEMBER
0 /usr/lpp/xlopt:/usr/lib:/lib
1 libc.a shr.o
Since libc.a has no path information, the system loader will look for this library from the directories (/usr/lpp/xlopt:/usr/lib/:/lib) listed in the first (index 0) loader header section of the XCOFF header of the generated executable file.
If the program is referencing libraries, then use the -L and -l linker options rather than specifying library file path names directly.
For example, if the referenced library, libabc.a, is placed in the /project/test/lib directory, specify the options as follows:
$ cc -o a.out main.c -labc -L/project/test/lib
The linker adds the /project/test/lib directory in front of the default directory search path in order to look for referenced shared objects and libraries.
In this case, the directory name, /project/test/lib, will be added to in front of the first entry for the first (index 0) loader header section of the XCOFF header of the generated executable file, as shown in Example 2-6.
$ dump -H a.out
a.out:
***Loader Section***
Loader Header Information
VERSION# #SYMtableENT #RELOCent LENidSTR
0x00000001 0x00000007 0x00000010 0x00000037
#IMPfilID OFFidSTR LENstrTBL OFFstrTBL
0x00000002 0x00000188 0x0000002a 0x000001bf
***Import File Strings***
INDEX PATH BASE MEMBER
0 /project/test/lib:/usr/lpp/xlopt:/usr/lib:/lib
1 libabc.a shr.o
|
When executing the command, if libabc.a is found in the directories shown in the following directories, the command can run:
/project/test/lib:/usr/lpp/xlopt:/usr/lib:/lib
Note
The shared objects and libraries must not have any optional path component information in the XCOFF loader header section to be searched from the directories listed in the first (index 0) loader header section of the executable file.
The linker can handle two types of files as input: object file or library. Those object files and libraries can be specified in the linker command line explained in this section.
Note
The order of libraries and objects specified on the linker command line is not important unless run-time linking (see 2.5, “Run-time linking” on page 68) is used.
Specify the absolute path name for the object file. For example:
$ cc -o a.out main.c /prod/obj/shr1.o
Specify the relative path name for the object file. For example:
$ cc -o a.out main.c ../../prod/obj/shr1.o
Specify the file name for the object file, if it resides in the current directory. For example:
$ ls main.c shr.o main.c shr.o $ cc -o a.out main.c shr1.o
Except for the last method, the generated executable file would have an optional path component for its dependent shared object shr.o in its XCOFF header, if shr.o is a shared object.
Specify the absolute path name for the library. For example:
$ cc -o a.out main.c /prod/lib/libabc.a
Specify the relative path name for the library. For example:
$ cc -o a.out main.c ../../prod/lib/libabc.a
Specify the file name for the library, if it resides in the current directory. For example:
$ ls main.c libabc.a libabc.a main.c $ cc -o a.out main.c libabc.a
Specify the library installed directory using the -L and -l linker options. For example:
$ cc -o a.out main.c -L/prod/lib -labc
Except for the last two methods, the generated executable file would have an optional path component for its dependent shared library libabc.a in its XCOFF header, if libabc.a is a shared library.
Note
The linker -bnoipath options instructs the command to not include any file path name information in the resultant module. The default option, -bipath, preserves file path name information.
If the LIBPATH[13] environment variable is defined, the system loader refers to it in order to search referenced shared objects and libraries that contain shared archive members, when the executable file is invoked. The linker does not refer to LIBPATH in order to look for shared objects and libraries.
[13] On some other UNIX operating systems the LD_LIBRARY_PATH variable is used for a similar purpose. On AIX, however, LD_LIBRARY_PATH has no meaning.
The syntax of LIBPATH is:
LIBPATH=/path1:/path2:/path3:...
If defined, the system loader does the following processes when loading modules:
1. | Adds the text string value of LIBPATH in front of the PATH information stored in the first (index 0) loader header section of the XCOFF header of the executable. |
2. | The system loader will search shared objects and libraries referenced by the executable in the directories in the order of the list created in the previous step. |
Note
When a non-root user is attempting to run a setuid or setgid executable, only the directories listed in the header section of the executable are searched; the LIBPATH variable is ignored, even if it is set.
For example, if the LIBPATH environment variable is defined as follows when executing the program example used in 2.3.1, “The -L linker option” on page 55:
LIBPATH=/project/build/lib
then the system loader will search for the referenced shared objects and libraries in the following order:
/project/build/lib
/project/test/lib
/usr/lpp/xlopt
/usr/lib
/lib
Note
The shared objects and libraries must not have any optional path component information in the XCOFF loader header section to be searched from the directories specified by the LIBPATH environment variable.
For example, assuming the following:
The shared object shr.o is linked with main.o in order to create the executable a.out.
Both shr.o and main.o are located in the current directory.
then you can select the following two methods to specify the file name shr.o in the command line to build the executable:
cc -o a.out main.o shr.o
cc -o a.out main.o ./shr.o
The executable file generated using the first method would have the loader information for shr.o, as shown in Example 2-7. In this case, the system loader will look for shr.o in the /usr/lpp/xlopt, /usr/lib, and /lib directories. If shr.o is stored in one of these directories, there is no need to set LIBPATH. If shr.o is stored in other than these directories, set the LIBPATH environment variable accordingly.
$ dump -H a.out
a.out:
***Loader Section***
Loader Header Information
VERSION# #SYMtableENT #RELOCent LENidSTR
0x00000001 0x00000007 0x00000010 0x00000036
#IMPfilID OFFidSTR LENstrTBL OFFstrTBL
0x00000003 0x00000188 0x0000002a 0x000001be
***Import File Strings***
INDEX PATH BASE MEMBER
0 /usr/lpp/xlopt:/usr/lib:/lib
1 libc.a shr.o
2 shr.o
|
For example, if shr.o is stored in the current directory, run the executable file after setting the variable as follows:
$ LIBPATH=$PWD ./a.out
If you have moved shr.o to /project/lib, then do the following:
$ LIBPATH=/project/lib ./a.out
If the executable is generated using the second method, the last five lines in Example 2-7 on page 59 would be:
***Import File Strings***
INDEX PATH BASE MEMBER
0 /usr/lpp/xlopt:/usr/lib:/lib
1 libc.a shr.o
2 . shr.o
The dot character in the PATH column for shr.o, which is an optional path component for shr.o, makes a big difference. When executing the executable generated with the second method, the system loader will not refer to LIBPATH nor the directories listed in the first (index 0) loader header section, in order to search shr.o. Therefore, shr.o must be located in the current directory whenever the executable file is invoked.
If a shared object cannot be found by the system loader when trying to start an executable, an error message similar to the following will be seen:
exec(): 0509-036 Cannot load program ex1 because of the following errors: 0509-022 Cannot load library libone.so. 0509-026 System error: A file or directory in the path name does not exist.
The missing objects will be listed with 0509-022 error messages. Use the find command to search the system for the missing shared objects. If the object is found, try setting the LIBPATH environment variable to include the directory that contains the shared object and restart the application. Also, ensure that the object or library has read permission for the user trying to start the application.
A similar error message is produced when the system loader finds the specified shared objects, but not all of the required symbols can be resolved. This can happen when an incompatible version of a shared object is used with an executable. The error message is similar to the following:
exec(): 0509-036 Cannot load program ./example because of the following errors: 0509-023 Symbol func1 in ex1 is not defined. 0509-026 System error: Cannot run a file that does not have a valid format.
The unresolved symbols are listed in the 0509-023 message lines. Write down the name of the unresolved symbol (func1), and use the dump -Tv command to determine which shared object the executable expects to resolve the symbol from. For example:
# dump -Tv example | grep function1 [4] 0x00000000 undef IMP DS EXTref libone.a(shr1.o) func1
This indicates that the executable is expecting to resolve the symbol func1 from the shared object shr1.o that is an archive member of libone.a. This information can help you start the problem determination process.
Note
To solve typical link-time errors, see 6.3, “Diagnosing link-time errors” on page 239.
Shared objects and libraries are used in two stages when creating and executing an executable on AIX:
At link-time, the link editor (the ld command) searches the specified shared objects and libraries to resolve all undefined symbols that are referenced in the generating executable file. If a shared object file or library contains the referenced symbols, the loader section of the XCOFF header of the created executable file should contain a reference to that shared object or library.
In other words, symbols are exported from those shared objects or libraries and imported from the executable file.
At the program load-time, the system loader (the kernel component that starts new processes) reads the XCOFF header information of the executable and attempts to locate any referenced shared libraries. Assuming all the referenced shared objects and libraries are found, the executable can be started. Then, the system loader attempts to load the sections in the executable file into the appropriate segments in the process address space, as explained in Table 2-2 on page 62. The program text in shared objects and libraries is loaded into the global system memory by the first program that needs it and is shared by all programs that use it.
Program executable components | Corresponding section header name in the XCOFF format | Loading target segment in the process address space |
---|---|---|
Program text | .text | Process text segment |
Program data (initialized and un-initialized) | .data and .bss | Process data segment |
Referenced shared objects | loader | Shared library text segment (per-process shared library data segment will be also populated with the necessary data for the process) |
For the detailed information about the each segment usage in the process address space, see Chapter 3, “Understanding user process models” on page 105.
Figure 2-3 on page 63 depicts the processes done by the system loader at the program load-time.
Technically, each section header in the XCOFF file provides an offset address to the actual section in the file. However, this is not shown in Figure 2-3 to avoid unnecessary complexity.