2.5. Run-time linking

As explained in 2.4.1, “AIX default linking” on page 64, all referenced symbols must be resolved at link-time when building executable files using the default, static, and lazy loading link methods on AIX. Those pre-resolved symbols cannot be rebound after the executable files are created.

The run-time link method, or run-time linking, enables a program to resolve its referenced symbols at the program load-time rather than link-time. It is the ability to resolve undefined and non-deferred symbols in shared modules after the program execution has already began. It is a mechanism for providing run-time definitions (for example, function definitions that are not available at the program link-time) and symbol rebinding capabilities. For example, if main() calls func1() in libfunc1.so, which then calls func2() in libfunc2.so, assuming that libfunc1.so and libfunc2.so were built to enable run-time linking, then the main application could provide an alternate definition of func2() that would override the one originally found in libfunc2.so.

Please note that it is the main application that has to be built to enable run-time linking. Simply linking a module with the run-time link library is not enough. This structure allows a module to be built to support run-time linking, yet continue to function in an application that has not been so enabled.

Note

In AIX, even if the run-time link method is used, all symbols except for the deferred symbols (see “Displaying symbol definition with dump -Tv” on page 87 for the definition of deferred symbols) must be resolved at the program load-time. However, in some other UNIX operating systems, resolution of function symbols is deferred until the function is first called (references to variables must be resolved at load-time). This allows the definition for a function to be loaded after the module referring to that symbol is loaded on those operating systems.


In order to use the run-time link method, the following points must be understood:

  • The run-time link method is enabled by the run-time link library (/usr/lib/librtl.a) specified by the -brtl option when generating the executable file. The -brtl option is mutually exclusive with the -blazy option.

  • Only run-time linking shared objects are run-time linked. Objects or archive members other than run-time shared objects are linked in the default link method.

  • Run-time linking shared objects must be created before linking them with the main program, as explained in “Creating run-time linking shared objects” on page 71.

  • Run-time linking shared objects should use the file name convention libname.so. If this naming convention is used, it is easy to distinguish run-time linking shared objects from other types of objects and easy to specify the file path name on the command line (see 2.5.5, “Extended search order with the -brtl linker option” on page 81).

An advantage of using run-time linking is that developers do not need to maintain a list of module interdependencies and import/export lists (see 2.8.1, “Import and export files” on page 92). By using the -bexpall linker option, all shared objects can export all symbols, and the run-time linker can be used to resolve the inter-module dependencies.

2.5.1. How to use run-time linking

This section explains how to use run-time linking by providing several simple examples.

Sample program source files

Our example program is composed of four C program source files, main.c (shown in Example 2-8), func1.c (Example 2-9), func2.c, and func3.c (Example 2-10). The source file of func2.c is the same as func3.c, except that the function name is func2, not func3.

Example 2-8. Run-time linking example (main.c)
#include <stdio.h>
#include <stdlib.h>

extern void func1(void);

int main(int argc, char *argv[])
{
        func1();
}

Example 2-9. Run-time linking example (func1.c)
#include <stdio.h>
#include <stdlib.h>

void func1(void)
{
        printf("within function %s at line number: %d in %s
"
                , __FUNCTION__, __LINE__, __FILE__);
        func3();
}

Example 2-10. Run-time linking example (func3.c)
#include <stdio.h>
#include <stdlib.h>

void func3(void)
{
        printf("within function %s at line number: %d in %s
"
                , __FUNCTION__, __LINE__, __FILE__);
}

If this simple application is statically built as follows:

$ cc -c main.c func1.c func2.c func3.c
main.c:
func1.c:
func2.c:
func3.c:
$ ls main.o func1.o func2.o func3.o
func1.o  func2.o  func3.o  main.o
$ cc main.o func1.o func2.o func3.o

then the generated executable file a.out prints the following output:

$ ./a.out
within function func1 at line number: 7 in func1.c
within function func3 at line number: 7 in func3.c

Please note the function func2 in func2.c is not called at all in this application. This function is intentionally included in this example in order to show the important aspect of run-time linking in later sections.

Creating run-time linking shared objects

In order to use run-time linking, run-time linking shared objects must be created before linking them with the main program. To create a run-time linking shared object, do the following:

1.
Compile the source file and create an object file.

2.
Re-link the object file with the -G linker option and create a run-time linking shared object (.so).

Note

Multiple object files can be combined into a single run-time linking shared object file.

3.
Archive the created run-time linking shared object into a library archive (libname.a). This is an optional step.

In fact, these steps are very similar to the steps to create regular (run-time linking disabled) shared objects except for the specified linker options (see 2.8, “Creating shared objects” on page 92).

For example, to create three run-time linking shared objects from func1.c, func2.c, and func3.c, do the following:

$ cc -c func1.c func2.c func3.c
func1.c:
func2.c:
func3.c:
$ ld -G -o func1.so func1.o -bnoentry -bexpall
$ ld -G -o func2.so func2.o -bnoentry -bexpall -lc
$ ld -G -o func3.so func3.o -bnoentry -bexpall -lc
$ ls *.o *.so
func1.o   func1.so  func2.o   func2.so  func3.o   func3.so

The following linker options are specified in this example:

-bnoentryIndicates that the output file has no entry point. To retain any needed symbols, specify them with the -u flag or with an export file. You can also use the -r flag or the -bnogc or -bgcbtpass options to keep all external symbols in some or all object files. If neither the -bnoentry nor the -bnox option is used and the entry point is not found, a warning is issued.
-bexpallExports all global symbols, except imported symbols, unreferenced symbols defined in archive members, and symbols beginning with an underscore (_). You may export additional symbols by listing them in an export file. This option does not affect symbols exported by the -bautoexp option. This option only applies to AIX Version 4.2 and later.
 When you use this option, you may be able to avoid using an export file. On the other hand, using an export file provides explicit control over which symbols are exported, and allows you to use other global symbols within your shared object without worrying about conflicting with names exported from other shared objects. The default is -bnoexpall.
-lcSpecifies referenced libraries. As for func2.o and func3.o, the standard C library must be specified to resolve the symbol of printf(). In the case of func1.o, there is no need to specify any libraries, since it does not call any functions, except for func3.
-GThe -G linker option is equivalent to specifying all the options shown in Table 2-5 on page 73.

Table 2-5. Linker options equivalent to -G
OptionDescription
-berokEnables creation of the object file, even if there are unresolved references
-brtlEnables run-time linking. All shared objects listed on the command line (those that are not part of an archive member) are listed in the output file. The system loader loads all such shared modules when the program runs, and the symbols exported by these shared objects may be used by the run-time linker.
-bsymbolicAssigns this attribute to most symbols exported without an explicit attribute.
-bnortllibRemoves a reference to the run-time linker libraries. This means that the module built with the -G option (which contains the -bnortllib option) will be enabled for run-time linking, but the reference to the run-time linker libraries will be removed. Note that the run-time libraries should be referenced to link the main executable only.
-bnoautoexpPrevent automatic exportation of any symbol.
-bM:SREBuild this module to be shared and reusable.

For the detailed information about these linker options, please refer to the ld command section in the AIX 5L Version 5.2 Reference Documentation: Commands Reference.

Note

Compiler drivers also have the -G option. Do not use the compiler -G option to create run-time linking shared objects from object files.


Creating an executable with run-time linking shared objects

In order to create an executable linked with run-time linking shared objects, do the following:

1.
Compile the main program source file, which contains main(), and create an object file.

2.
Re-link this object file with the -G linker option and create a run-time linking shared object (.so).

3.
Link the object file compiled from the main program source file with run-time linking shared objects as well as the -brtl linker option specified.

If the object file created from the main program source file does not have be run-time linking enabled, then the required task is shorten as follows:

Use an appropriate compiler driver, not the linker, to compile the main program source file, which contains main(), then link the object file with run-time linking shared objects by specifying the -brtl option.

As for our program example, we have built the executable a.out as follows using the later simple method:

$ ls *.o *.so
func1.o   func1.so  func2.o   func2.so  func3.o func3.so
$ cc main.c func1.so func2.so func3.so -brtl
$ ls a.out
a.out

If executed, the program would print the following error message and fail to execute, since the dependent module func1.so could not be found by the system loader:

$ ./a.out
exec(): 0509-036 Cannot load program ./a.out because of the following errors:
        0509-150   Dependent module func1.so could not be loaded.
        0509-022 Cannot load module func1.so.
        0509-026 System error: A file or directory in the path name does not
exist.

If LIBPATH is set as follows, it executes as expected:

$ LIBPATH=$PWD ./a.out
within function func1 at line number: 7 in func1.c
within function func3 at line number: 7 in func3.c

If the linker command (ld) was used instead of the compiler driver (cc) as follows:

$ cc -c main.c
$ ld main.o func1.so func2.so func3.so -brtl

then the program would print the following error message, since the generated executable would not contain the necessary start up routine:

$ LIBPATH=$PWD ./a.out
exec(): 0509-036 Cannot load program ./a.out because of the following errors:
        0509-151 The program does not have an entry point or
                   the o_snentry field in the auxiliary header is invalid.
        0509-194 Examine file headers with the 'dump -ohv' command.

2.5.2. Examining the executable and shared objects using dump

By using the dump command, you can examine whether the generated executable is linked using run-time linking or not. For example, the dump command with the -H option shows the header information for our example application a.out, as shown in Example 2-11.

Example 2-11 includes two important lines (highlighted):

  • The run-time linking shared object func2.so is included in the dependent module list, though any symbols in this module are not referenced in the application at all.

    Note

    If this executable was compiled without -brtl, func2.so would not be included in the dependent module list.


  • The run-time linker, the archive member shr.o in librtl.a, is included in the dependent module list.

Example 2-11. dump -H a.out
$ dump -H a.out

a.out:

                        ***Loader Section***
                      Loader Header Information
VERSION#         #SYMtableENT     #RELOCent       LENidSTR
0x00000001       0x00000009       0x00000011      0x0000005e

#IMPfilID        OFFidSTR         LENstrTBL       OFFstrTBL
0x00000006       0x000001c4       0x0000002a      0x00000222


                        ***Import File Strings***
INDEX  PATH                          BASE               MEMBER
0      /usr/lpp/xlopt:/usr/lib:/lib
1                                    func1.so
2                                    func2.so
3                                    func3.so
4                                    libc.a             shr.o
5                                    librtl.a           shr.o
					

Note

The order of run-time linking shared objects listed in the executable’s header is same with the order of object files specified in the linker command line when generating the executable file:

$ cc main.c func1.so func2.so func3.so -brtl


The dump command with the -Tv option shows the referenced symbols information for our example application a.out, as shown in Example 2-12.

A very important fact in Example 2-12 is that there is no entry for the function func3, which is called from func1 in func1.c. As explained in 2.3, “Resolving symbols at link-time” on page 53, all symbols must be resolved at the program link-time, and all the resolved symbol information will be shown in the XCOFF loader section of the generated executable on AIX by default. However, in the case of run-time linking, symbols to be resolved by the run-time linker will not be shown in the XCOFF loader section of the generated executable, thus func3 is not shown in Example 2-12.

Example 2-12. dump -Tv a.out (1)
$ dump -Tv a.out

a.out:


                       ***Loader Section***

                       ***Loader Symbol Table Information***
[Index]      Value     Scn     IMEX Sclass   Type           IMPid Name

[0]     0x20000448   .data              RW SECdef        [noIMid] __rtinit
[1]     0x00000000   undef      IMP     RW EXTref   libc.a(shr.o) errno
[2]     0x00000000   undef      IMP     DS EXTref   libc.a(shr.o) exit
[3]     0x00000000   undef      IMP     DS EXTref   libc.a(shr.o) __mod_init
[4]     0x00000000   undef      IMP     BS EXTref   libc.a(shr.o) __crt0v
[5]     0x00000000   undef      IMP     BS EXTref   libc.a(shr.o) __malloc_user_defined_name
[6]     0x00000000   undef      IMP     DS EXTref        func1.so func1
[7]     0x00000000   undef      IMP     DS EXTref librtl.a(shr.o) __rtld
[8]     0x20000458   .data    ENTpt     DS SECdef        [noIMid] __start

Example 2-13 on page 77 shows the header information for the dependent shared object module func1.so. The double dot characters (..) in the last line indicate that at least one run-time linking shared objects are required in order to resolve unresolved symbols in this module.

Example 2-13. dump -H func1.so
$ dump -H func1.so

func1.so:


                        ***Loader Section***
                      Loader Header Information
VERSION#         #SYMtableENT     #RELOCent        LENidSTR
0x00000001       0x00000003       0x00000006       0x00000015

#IMPfilID        OFFidSTR         LENstrTBL        OFFstrTBL
0x00000002       0x000000b0       0x00000000       0x00000000


                        ***Import File Strings***
INDEX  PATH                          BASE                MEMBER
0      /usr/lib:/lib
1                                    ..

Example 2-14 shows the loader section information for the dependent shared object module func1.so. There are two imported symbols, printf and func3, in this module.[16] The double dot characters (..) in the IMPid column indicate that the symbol will be resolved by the run-time linker at the program load-time.

[16] See “Displaying symbol definition with dump -Tv” on page 87 how to interpret columns shown in the dump -Tv output.

Example 2-14. dump -Tv func1.so
$ dump -Tv func1.so

func1.so:


                       ***Loader Section***

                       ***Loader Symbol Table Information***
[Index]      Value     Scn     IMEX Sclass   Type           IMPid Name

[0]     0x00000050   .data      EXP     DS SECdef        [noIMid] func1
[1]     0x00000000   undef      IMP     DS EXTref              .. printf
[2]     0x00000000   undef      IMP     DS EXTref              .. func3

Figure 2-6 on page 78 depicts the function calling relationship for our application built in this section. The run-time linking shared object func2.so is referenced by the executable file (a.out) and will be loaded into the system memory by the system loader at the program execution time, even if a symbol in this object is not referenced by the executable.

Figure 2-6. Function calling relationship


2.5.3. Enabling the main program object as run-time linking

If you closely examine Example 2-12 on page 76, you notice that func1.so was not linked as a run-time linking shared object. The IMPid column of the func1 symbol shows the file name of func1.so, thus it is treated as a regular shared object. The reason is that the object file created from the main program source file, which includes main(), had not been run-time linking enabled, therefore all dependent modules that were required to resolve symbols referenced by main.o had to be loaded at the program load-time by the system loader.

In order to enable the main program object as a run-time linking shared object, we could have done the following (highlighted lines and command options are different):

$ cc -c main.c func1.c func2.c func3.c
main.c:
func1.c:
func2.c:
func3.c:
$ ld -G -o main.so main.o -bexpall
ld: 0711-327 WARNING: Entry point not found: __start
$ ld -G -o func1.so func1.o -bnoentry -bexpall
$ ld -G -o func2.so func2.o -bnoentry -bexpall -lc
$ ld -G -o func3.so func3.o -bnoentry -bexpall -lc
$ cc -o a.out main.so func1.so func2.so func3.so -brtl
					

After specifying LIBPATH, the program prints the following output as expected:

$ LIBPATH=$PWD ./a.out
within function func1 at line number: 7 in func1.c
within function func3 at line number: 7 in func3.c

Example 2-15 on page 79 shows the referenced symbol information for a.out generated by the compiler driver. Please note that Example 2-15 on page 79 does not contain the symbol information for either func1 or func3.

Example 2-15. dump -Tv a.out (2)
$ dump -Tv a.out

a.out:

                       ***Loader Section***

                       ***Loader Symbol Table Information***
[Index]      Value     Scn     IMEX Sclass   Type           IMPid Name

[0]     0x200003e8   .data              RW SECdef        [noIMid] __rtinit
[1]     0x00000000   undef      IMP     RW EXTref   libc.a(shr.o) errno
[2]     0x00000000   undef      IMP     DS EXTref   libc.a(shr.o) exit
[3]     0x00000000   undef      IMP     DS EXTref   libc.a(shr.o) __mod_init
[4]     0x00000000   undef      IMP     BS EXTref   libc.a(shr.o) __crt0v
[5]     0x00000000   undef      IMP     BS EXTref   libc.a(shr.o) __malloc_user_defined_name
[6]     0x00000000   undef      IMP     DS EXTref         main.so main
[7]     0x00000000   undef      IMP     DS EXTref librtl.a(shr.o) __rtld
[8]     0x200003f8   .data    ENTpt     DS SECdef        [noIMid] __start

Although, it is technically possible to link all dependent shared objects in an application using run-time linking, it should be avoided in order for the application performance. In general, to take advantage of the AIX architecture, the shared modules should be as self contained as possible. Run-time linking should be used only when necessary. Application program code ported from other UNIX operating systems often does not have this sort of organization and can therefore require extra effort to enable it on AIX. It is important to emphasize the fact that the performance and efficiency of AIX is best explained by a well organized application structure with a well defined interface between modules.

2.5.4. Rebinding symbols at the program load-time

Example 2-16 on page 80 and Example 2-17 on page 80 respectively show the symbol information for func2.so and func3.so used in 2.5.1, “How to use run-time linking” on page 70. Although these objects themselves are run-time linking enabled, they have no dependent run-time linking shared object.

Example 2-16. dump -Tv func2.so
$dump -Tv func2.so

func2.so:


                        ***Loader Section***

                        ***Loader Symbol Table Information***
[Index]      Value      Scn     IMEX Sclass   Type           IMPid Name

[0]     0x00000000    undef      IMP     DS EXTref   libc.a(shr.o) printf
[1]     0x00000050    .data      EXP     DS SECdef        [noIMid] func2

Example 2-17. dump -Tv func3.so
$ dump -Tv func3.so

func3.so:


                       ***Loader Section***

                       ***Loader Symbol Table Information***
[Index]      Value     Scn     IMEX Sclass   Type           IMPid Name

[0]     0x00000000   undef      IMP     DS EXTref   libc.a(shr.o) printf
[1]     0x00000050   .data      EXP     DS SECdef        [noIMid] func3

If func2.so and func3.so are swapped as follows, the new func2.so will contain the function func3 and the new func3.so will contain func2:

$ mv func3.so temp.so
$ mv func2.so func3.so
$ mv temp.so func2.so

After func2.so and func3.so swapped, the run-time linker looks for the symbol definition for func3 and found in the new func2.so in the order of func1.so, func2.so, and func3.so. The referenced symbol func3 is rebound at the program load-time without re-linking the application, thus the executable prints the following output:

$LIBPATH=$PWD ./a.out
within function func1 at line number: 7 in func1.c
within function func3 at line number: 7 in func3.c

Figure 2-7 on page 81 depicts the function calling relationship for our application after swapping func2.so and fun3.so. Now, new func2.so, which was originally func3.so, contains func3, and new func3.so, which was originally func2.so, contains func2.

Figure 2-7. Function calling relationship after rebinding symbols


The run-time linking shared object func3.so is required by the executable file (a.out) and will be loaded into the system memory by the system loader at the program execution time, even if no symbol in this object is not referenced by the executable.

2.5.5. Extended search order with the -brtl linker option

When an executable file is linked in the run-time link method by specifying the -brtl linker option, the linker uses the extended search order to look for the shared objects and libraries to resolve symbols. In order to exploit this extended search order, run-time linking shared objects must follow the file name convention libname.so.

If the -brtl linker option is specified, the linker looks for libname.so, as well as libname.a, in the directories specified by the -L linker option in addition to the default directory search path (/usr/lib and /lib). The -lname linker option can be also used to specify libname.so as well as libname.a.

For example, if a run-time linking shared object named libfunc1.so, which is stored in the /project/lib directory, is linked when generating the executable file a.out, there are several methods to specify the object:

  • cc main.c /project/lib/libfunc1.so -brtl

    This method almost invalidates the merit of the run-time link method. Although libfunc1.so is loaded at the program load-time, it must reside in the /project/lib directory when the executable is invoked.

  • cp /project/lib/libfunc1.so .; cc main.c libfunc1.so -brtl

    This method is useful if all the run-time linking shared objects are located in the current directory. However, once a stable version is developed, those objects are most likely deployed in a specific directory. Therefore, it is less useful compared to the third method.

  • cc main.c -lfunc1 -L/project/lib -brtl

    This is the recommended method to generate an executable file using the run-time link method. The linker looks for the specified run-time shared objects in the order explained in 2.3.1, “The -L linker option” on page 55.

    Note

    This method can be used only if the run-time shared object’s file name follows the libname.so naming convention.


To follow the libname.so naming convention, either rename the run-time linking shared object files or archive them into a library.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset