dlopen()

Open a shared library

Synopsis:

#include <dlfcn.h>

void * dlopen( const char * pathname, 
               int mode );

Arguments:

pathname
NULL, or the path to the shared library that you want to access.
mode
Flags that control how dlopen() operates. POSIX defines these bits:
  • RTLD_LAZY
  • RTLD_NOW
  • RTLD_GLOBAL
  • RTLD_LOCAL

The following bits are Unix extensions:

  • RTLD_NOLOAD
  • RTLD_GROUP
  • RTLD_WORLD
  • RTLD_NODELETE

The following bits are QNX Neutrino extensions:

  • RTLD_NOSHARE
  • RTLD_LAZYLOAD

For more information, see The mode,” below.

Library:

libc

Use the -l c option to qcc to link against this library. This library is usually included automatically.

Description:

The dlopen() function gives you direct access to the dynamic linking facilities by making the shared library specified in pathname available to the calling process. It returns a handle that you can use in subsequent calls to dlsym() and dlclose().

Note:
  • In order to successfully call this function, your process must have the PROCMGR_AID_PROT_EXEC ability enabled. For more information, see procmgr_ability().
  • If your process has any privileged abilities enabled, then the shared library you're trying to open must be trusted. For more information, see the description of PROT_EXEC in the entry for mmap(), as well as the entry for pathtrust in the Utilities Reference.
  • The dlopen() function is available only to a dynamically-linked process. A statically-linked process (one where libc is linked statically) can't call dlopen() because a statically-linked executable:
    • doesn't export any of its symbols
    • can't export the required structure for libraries to link against
    • can't fill structures at startup needed to load subsequent shared objects

Any dependencies recorded within pathname are loaded as part of the dlopen() call. These dependencies are searched in load-order to locate any additional dependencies. This process continues until all of the dependencies for pathname have been satisfied. This dependency tree is called a group.

If pathname is NULL, dlopen() provides a handle to the running process's global symbol object. This provides access to the symbols from the original program image file, the dependencies it loaded at startup, plus any objects opened with dlopen() calls using the RTLD_GLOBAL flag. This set of symbols can change dynamically if the application subsequently calls dlopen() using RTLD_GLOBAL.

You can use dlopen() any number of times to open objects whose names resolve to the same absolute or relative path name; the object is loaded into the process's address space only once.

In order to find the shared objects, dlopen() searches the following, in this order:

Note: For security reasons, the runtime linker unsets LD_LIBRARY_PATH if the binary has the setuid bit set.

The above directories are set as follows:

When loading shared objects, the application should open a specific version instead of relying on the version pointed to by a symbolic link.

The mode

The mode argument indicates how dlopen() operates on pathname when handling relocations, and controls the visibility of symbols found in pathname and its dependencies.

The mode argument is a bitwise-OR of the constants described below. Note that the relocation and visibility constants are mutually exclusive.

Relocation

When you load an object by calling dlopen(), the object may contain references to symbols whose addresses aren't known until the object has been loaded; these references must be relocated before accessing the symbols. The mode controls when relocations take place, and can be one of:

RTLD_LAZY
(QNX Neutrino 6.5.0 and later) References to data symbols are relocated when the object is loaded. References to functions aren't relocated until that function is invoked. This improves performance by preventing unnecessary relocations.
RTLD_NOW
All references are relocated when the object is loaded. This may waste cycles if relocations are performed for functions that never get called, but this behavior could be useful for applications that need to know that all symbols referenced during execution are available as soon as the object is loaded.

Visibility

The following mode bits determine the scope of visibility for symbols loaded with dlopen():

RTLD_GLOBAL
Make the object's global symbols available to any other object that's opened later with RTLD_WORLD. Symbol lookup using dlopen( 0, mode ) and an associated dlsym() are also able to find the object's symbols.
RTLD_LOCAL
Make the object's global symbols available only to objects in the same group.
RTLD_LAZYLOAD
Open the shared object and form its resolution scope by appending its immediate dependencies. This is different from the normal resolution scope, which is formed by appending the whole dependency tree in breadth-first order. For more information, see Lazy loading in the Compiling and Debugging chapter of the QNX Neutrino Programmer's Guide.

The program's image and any objects loaded at program startup have a mode of RTLD_GLOBAL; the default mode for objects acquired with dlopen() is RTLD_LOCAL. A local object may be part of the dependencies for more than one group; any object with a RTLD_LOCAL mode referenced as a dependency of an object with a RTLD_GLOBAL mode is promoted to RTLD_GLOBAL.

Objects loaded with dlopen() that require relocations against global symbols can reference the symbols in any RTLD_GLOBAL object.

Symbol scope

You can OR the mode with the following values to affect the symbol scope:

RTLD_GROUP
Only symbols from the associated group are available. All dependencies between group members must be satisfied by the objects in the group.
RTLD_WORLD
Only symbols from RTLD_GLOBAL objects are available.

If you don't specify either of these values, dlopen() uses RTLD_WORLD | RTLD_GROUP.

Note: If you specify RTLD_WORLD without RTLD_GROUP, dlopen() doesn't load any of the DLL's dependencies.

Other flags

The following flags provide additional capabilities:

RTLD_NODELETE
Don't delete the specified object from the address space as part of a call to dlclose().
RTLD_NOLOAD
Don't load the specified object, but return a valid handle if if the object already exists as part of the process address space. You can specify addition modes, which are ORed with the present mode of the object and its dependencies. This flag gives you a means of querying the presence or promoting the modes of an existing dependency.
RTLD_NOSHARE
Don't share the specified object. This flag forces the loading of multiple instances of libraries.

Symbol resolution

When resolving the symbols in the shared object, the runtime linker searches for them in the dynamic symbol table using the following order:

By default:
  1. main executable
  2. the shared object being loaded
  3. objects specified by the LD_PRELOAD environment variable
  4. all other loaded shared objects that were loaded with the RTLD_GLOBAL flag
When -Bsymbolic is specified:
  1. the shared object being loaded
  2. main executable
  3. objects specified by the LD_PRELOAD environment variable
  4. all other loaded shared objects that were loaded with the RTLD_GLOBAL flag
Note: For security reasons, the runtime linker unsets LD_PRELOAD if the binary has the setuid bit set.

For executables, the dynamic symbol table typically contains only those symbols that are known to be needed by any shared libraries. This is determined by the linker when the executable is linked against a shared library.

Since you don't link your executable against a shared object that you load with dlopen(), the linker can't determine which executable symbols need to be made available to the shared object.

If your shared object needs to resolve symbols in the executable, then you may force the linker to make all of the symbols in the executable available for dynamic linking by specifying the -E linker option. For example:

qcc -Vgcc_ntox86 -Wl,-E -o main main.o

Shared objects always place all their symbols in dynamic symbol tables, so this option isn't needed when linking a shared object.

Returns:

A handle to the object, or NULL if an error occurs.

Note: Don't interpret the value of this handle in any way. For example, if you open the same object repeatedly, don't assume that dlopen() returns the same handle.

Errors:

If an error occurs, more detailed diagnostic information is available from dlerror().

Environment variables:

Note: For security reasons, the runtime linker unsets DL_DEBUG, LD_DEBUG, LD_DEBUG_OUTPUT, LD_LIBRARY_PATH, and LD_PRELOAD if the binary has the setuid bit set.
DL_DEBUG
If this environment variable is set, the shared library loader displays debugging information about the libraries as they're opened. The value can be a comma-separated list of the following:
  • all — display all debug messages.
  • help — display a help message, and then exit.
  • reloc — display relocation processing messages.
  • libs — display information about shared objects being opened.
  • statistics — display runtime linker statistics.
  • lazyload — print lazy-load debug messages.
  • debug — print various runtime linker debug messages.

A value of 1 (one) is the same as all.

LD_BIND_NOW
Affects lazy-load dependencies due to full symbol resolution. Typically, it forces the loading of all lazy-load dependencies (until all symbols have been resolved).
LD_DEBUG
A synonym for DL_DEBUG. If you set both DL_DEBUG and LD_DEBUG, then DL_DEBUG takes precedence.
LD_DEBUG_OUTPUT
The name of a file in which the runtime linker writes its output. By default, output is written to stderr.
LD_LIBRARY_PATH
A colon-separated list of directories to search for shared libraries. Blank entries in the list are treated as “.”, meaning they refer to the current working directory. This can include the following cases:
  • The entire list is blank (i.e., LD_LIBRARY_PATH="" was specified), which is different from the variable being unset.
  • The list has a colon at the beginning (i.e., the first entry is blank), or it has two consecutive colons (i.e., the entry in between is blank).
LD_PRELOAD
A list of full paths to the shared libraries on an ELF system that you want to load before loading other libraries. Use a colon (:) to separate the libraries in this list. You can use this environment variable to add or change functionality when you run a program.

Classification:

POSIX 1003.1

Safety:  
Cancellation point Yes
Interrupt handler No
Signal handler No
Thread Yes

Caveats:

Some symbols defined in executables or shared objects might not be available to the runtime linker. The symbol table created by ld for use by the runtime linker might contain a subset of the symbols defined in the object.