2.6. Dynamic loading

Dynamic loading is the process in which one can attach a shared library to the address space of the process during execution, look up the address of a function in the library, call that function, and then detach the shared library when it is no longer needed. It is implemented as an interface to the services of the dynamic linker. This gives programmers extra control in managing the memory allocated to the shared library segment in an effective manner.

The dlopen() family of subroutines is supported on the AIX operating system. The functions include:

  • dlopen()

  • dlclose()

  • dlsym()

  • dlerror()

dlopen()

The dlopen() subroutine is used to open a shared object, and dynamically map it into the running programs address space. The syntax of the subroutine is as follows:

#include <dlfcn.h>

void *dlopen (FilePath, Flags);
const char *FilePath;
int Flags;

The FilePath parameter is the full path to a shared object, for example, shrobj.o, or libname.so. It can also be a pathname to an archive library that includes the required shared object member name in parenthesis, for example, /lib/libc.a(shr1.o).

The Flags parameter specifies how the named shared object should be loaded. The Flags parameter must be set to RTLD_NOW or RTLD_LAZY. If the object is a member of an archive library, the Flags parameter must be OR’ed with RTLD_MEMBER.

The subroutine returns a handle to the shared library that gets loaded. This handle is then used to with the dlsym subroutine to reference the symbols in the shared object. On failure, the subroutine returns NULL. If this is the case, the dlerror() subroutine can be used to print an error message.

Note

On AIX, the handle from dlopen() is specific to an instance of dlopen(). The dlclose() call only closes the instance of the object to which the handle refers.


dlsym()

The dlopen() subroutine is used to load the library. If successful, it returns a handle for use with the dlsym() routine to search for symbols in the loaded shared object. Once the handle is available, the symbols (including functions and variables) in the shared object can be found easily. For example:

lib_func = dlsym(lib_handle, "locatefn");
error = dlerror();
if (error) {
    fprintf(stderr, "Error:%s 
",error);
    exit(1);
}

The dlsym() subroutine accepts two parameters. The first is the handle to the shared object returned from the dlopen() subroutine. The other is a string representing the symbol to be searched for.

If successful, the dlsym() subroutine returns a pointer that holds the address of the symbol that is referenced. On failure, the dlsym subroutine returns NULL. This, again, can be used with the dlerror subroutine to print an error message as shown above.

dlclose()

The dlclose() subroutine is used to remove access to a shared object that was loaded into the processes’ address space with the dlopen subroutine. The subroutine takes as its argument the handle returned by dlopen().

dlerror()

The dlerror() subroutine is used to obtain information about the last error that occurred in a dynamic loading routine (that is, dlopen, dlsym, or dlclose). The returned value is a pointer to a null-terminated string without a final newline. Once a call is made to this subroutine, subsequent calls without any intervening dynamic loading errors will return NULL.

Applications can avoid calling the dlerror() subroutine, in many cases, by examining errno after a failed call to a dynamic loading routine. If errno is ENOEXEC, the dlerror() subroutine will return additional information. In all other cases, it will return the string corresponding to the value of errno.

Note

The dlerror() subroutine is not thread-safe.


Using dynamic loading subroutines

In order to use the dynamic loading subroutines, an application must be linked with the libdl.a library. The shared objects used with the dynamic loading subroutines can be traditional AIX shared objects or shared objects that have been enabled for run-time linking with the -G linker option.

When the dlopen() subroutine is used to open a shared object, any initialization routines specified with the -binitfini option, as described in 2.8.4, “Initialization and termination routines” on page 99, will be called before dlopen returns. Similarly, any termination routines will be called by the dlclose subroutine.

Advantages of dynamic loading

Use of dynamic loading allows several benefits for application developers:

  • The ability to share commonly-used code across many applications, leading to disk and memory savings.

  • It allows the implementation of services to be hidden from applications.

  • It allows the re-implementation of services, for example, to permit bug and performance fixes or to allow multiple implementations selectable at run time.

The following example program is used to demonstrate the use of dynamic loading subroutines:

/* File: main.c */

#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>

int main(int argc, char *argv[])
{
    void *handle;
    void (*fct)();

    printf("hello from main()
");

    if ((handle = dlopen("libfoo.so", RTLD_NOW)) == NULL) {
        perror("dlopen");
        exit(1);
    }
    if ((fct = (void (*)())dlsym(handle, "foo_")) == NULL) {
        perror("dlsym");
        exit(1);
    }
    (*fct)();
    printf("exit from main()
");
    dlclose(handle);
}

/* File : foo.c - Shared library libfoo.so */

#include <stdio.h>
#include <stdlib.h>

void foo_(void)
{
    printf("hello from foo_()
");
}

Compile the program as follows:

$ cc -c foo.c
$ ld -o libfoo.so foo.o -bM:SRE -bnoentry -bexpall -lc
$ cc -o main main.c

The program will print the following output if libfoo.so is successfully found and loaded by the dynamic linker:

hello from main()
hello from foo_()
exit from main()

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

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