dlopen - open a shared object
cc [flag ...] file ... -lc [library ...]
void *dlopen(const char *pathname, int mode);
dlopen is one of a family of routines that give the user direct access to
the dynamic linking facilities. These routines are available in a library
which is loaded if the option -lc is used with cc , f77 or ld.
dlopen makes a shared object available to a running process. dlopen
returns to the process a handle which the process may use on subsequent
calls to dlsym and dlclose. This handle should not be interpreted in any
way by the process. pathname is the path name of the object to be
opened; it may be an absolute path or relative to the current directory.
If the value of pathname is 0, dlopen makes the symbols contained in the
original a.out, and all of the objects that were loaded at program
startup with the a.out, available through dlsym.
When a shared object is brought into the address space of a process, it
may contain references to symbols whose addresses are not known until the
object is loaded. These references must be relocated before the symbols
can be accessed. The mode parameter governs when these relocations take
place and may have the following values:
RTLD_LAZY [Toc] [Back]
Only references to data symbols are relocated when the object is
loaded. References to functions are not relocated until a given
function is invoked for the first time. This mode should result in
the best performance, since a process may not reference all of the
functions in any given shared object. RTLD_LAZY cannot be combined
RTLD_NOW [Toc] [Back]
All necessary relocations are performed when the object is first
loaded. This may result in some wasted effort if relocations are
performed for functions that are never referenced, but is useful for
programs that need to know as soon as an object is loaded that all
symbols referenced during execution are available. RTLD_NOW cannot
be combined with RTLD_LAZY.
RTLD_GLOBAL [Toc] [Back]
modifies the treatment of the symbols in the DSO being opened to be
identical to those of sgi_dladd(). RTLD_GLOBAL may be or'd with
either RTLD_NOW or RTLD_LAZY (RTLD_GLOBAL cannot be the mode value
on its own). RTLD_GLOBAL See "NAMESPACE ISSUES" below for more on
the impact of using or not using RTLD_GLOBAL. With RTLD_GLOBAL the
handle is less necessary than without it, since rld directly
resolves references to symbols when RTLD_GLOBAL is provided and
dlsym is not needed.
The following is an example of use, using -32.
/* Error handling code not shown.
typedef int (*xamplefuncptr)(int);
handle = dlopen("greetings.so", RTLD_LAZY);
fptr = (xamplefuncptr)dlsym(handle, "greetings");
i = (*fptr)(3);
int greetings(int num_greetings)
for (i=0; i < num_greetings; i++)
printf ("hello world0);
% cc -32 -c dltry.c greetings.c
% ld -32 -shared greetings.o \
-soname greetings.so -o greetings.so
% cc -32 dltry.o
This section does not address symbol resolution from dlsym(3). See dlsym
for details on its symbol resolution rules.
Name resolution can become surprisingly complicated and non-intuitive in
the presence of programs or DSOs using dlopen, sgidladd,
sgi_dlopen_version, or LL_DELAY_LOAD (the ld -delay_load option).
Any case in which there is only one definition of a symbol across all
loaded DSOs is simple: that definition is used if it is visible
(visibility is discussed below).
Name searches are done in the order of a single list, the rld-list. The
first rld-list entry is the program itself. Following that is the list
of DSOs currently in the runtime of the program. At program startup a
breadth-first list of DSOs in the program (and, recursively their library
lists) is formed in the rld-list. No DSO is added to the rld-list twice
(later encounters of a DSO in simply use the earlier occurrence, but see
NOTES below for an exception). For any DSO library list entry marked
LL_DELAY_LOAD the DSO referenced is not loaded at program startup.
The above name search rule has an exception. If a DSO is marked as
DT_SYMBOLIC (see the ld option -B symbolic) then all name searches from
within that DSO begin at the DSO itself and continue with the standard
When, as a result of a call to a function in a LL_DELAY_LOADed DSO, that
DSO is loaded, the new DSO is added at the end of the rld-list (if it has
any entries in its library list that are not marked LL_DELAY_LOAD the
non-LL_DELAY_LOAD DSOs are added, recursively (breadth-first)). Thus,
depending on the order of calls to delay-loaded DSOs, the order of DSOs
on the rld-list may be different from one run of a program to the next.
The order of DSOs in the rld-list may not match the order in any given
library list because if a DSO is already in the rld-list it is not added
a second time to the rld-list.
As a result of the rule that the search order is rld-list order, the
symbol found can be surprising. Consider a symbol A found in DSOs B and
C and DSO B is before DSO C in E's liblist while DSO B is after DSO C in
F's liblist. Lets specify that neither DSO B nor DSO C are otherwise
referenced. If DSO E is dlopen(...RTLD_GLOBAL)ed before DSO F then the A
from DSO B is found by dlsym from either handle. While if DSO F is
dlopen(...RTLD_GLOBAL)ed before DSO E then the A from DSO C is found by
dlsym from either handle. On the other hand, if only one of the DSOs E
or F is dlopen(...RTLD_GLOBAL)ed then one gets DSO B's A from DSO E's
handle and one gets DSO C's A from DSO F's handle.
Note that dlclose does not cause any reordering of the rld-list: when the
last handle (direct or indirect) on a DSO is dlclosed the DSO is removed
from the rld-list. Before the final dlclose the DSO remains where it was
on the rld-list.
Now we turn to the issue of symbol visibility.
DSOs loaded by a single invocation of dlopen may import symbols from one
another or from any DSO which is globally-visible, but DSOs loaded by one
dlopen invocation may not directly reference symbols from DSOs loaded by
a different dlopen invocation. Those symbols may, however, be referenced
indirectly using dlsym.
Globally-visible DSOs are those added at program startup or via delayload
from a globally-visible object. In addition, any DSO added by
sgidladd or dlopen(...RTLD_GLOBAL...) or
sgidlopen_version(...RTLD_GLOBAL...) is globally-visible.
Even in a globally-visible DSO a symbol is invisible to any access from
outside the DSO if the symbol is marked STO_HIDDEN (see the ld options
-hidden_symbol or -hides_file for example). From within a DSO, all
symbols in that DSO are visible. From within a DSO, all globally-visible
symbols are visible.
Consider a set of DSOs.
ld -shared -all F.a -o F.so
ld -shared -all G.a -o G.so
ld -shared -all E.a F.so G.so -o E.so
ld -shared -all H.a F.so -o H.so
Say a program does dlopen("E.so",RTLD_LAZY) and and
dlopen("H.so",RTLD_LAZY) and uses dlsym to find functions through the two
handles and calls these two functions. Say each of these calls a function
that calls ff() in F.so. Say that ff() calls fg() which is only defined
in G.so. Logically one would say that the call through the function
accessed via E.so should resolve to fg() in G.so and one would think that
the call thru the function accessed via H.so should result in an
undefined function. However, rld does not attempt to determine (by
walking the run-time stack or other means) the exact call-stack to ff()
(the call-stack is not really enough: rld needs to know the handle used
to derive the calls!). The result of the call to fg() is undefined.
What happens is that fg() in G.so is called, since such would be legal if
the call path were thru E.so's handle. It is unwise to depend on such
SEARCHING FOR SHARED OBJECTS [Toc] [Back]
If other shared objects were link edited with pathname when pathname was
built, those objects are automatically loaded by dlopen (subject to the
LL_DELAY_LOAD library list flag). The directory search path that is used
to find both pathname and the other needed objects is the same as that
used by rld(1). In particular, pathname is searched for in
1) the directory specified by pathname if it is not a simple file name
(i.e. it contains a / character). In this case, the exact file is the
only placed searched; steps two through four below are ignored.
2) any path specified via the -rpath argument to ld(1) when the
executable was statically linked.
3) any directory specified by the environment variable LD_LIBRARY_PATH.
This environment variable should contain a colon-separated list of
directories, in the same format as the PATH variable [see sh(1)]. 64-bit
programs examine the variable LD_LIBRARY64_PATH, and if it is not set
LD_LIBRARY_PATH is examined. New 32-bit ABI programs examine the
variable LD_LIBRARYN32_PATH and if it is not set LD_LIBRARY_PATH is
All of these variables are ignored if the process is running setuid or
setgid [see exec(2)].
4) the default search paths are used. These are /usr/lib:/lib for 32-bit
programs, /usr/lib64:/lib64 for 64-bit programs, and /usr/lib32:/lib32
for new 32-bit ABI programs.
The variable _RLD_ROOT has its usual effect, as documented on rld(1)
(which means that if the process is running setuid or setgid _RLD_ROOT is
dlerror(3), dlclose(3), sgidladd(3), sgidlopen_version(3), dlsym(3),
If pathname cannot be found, cannot be opened for reading, is not a
shared object, or if an error occurs during the process of loading
pathname or relocating its symbolic references, dlopen returns NULL.
More detailed diagnostic information is available through dlerror.
Objects whose names resolve to the same absolute or relative path name
may be opened any number of times using dlopen, however, the object
referenced is only loaded once into the address space of the current
process. The same object referenced by two different path names,
however, may be loaded multiple times. For example, given the object
/usr/home/me/mylibs/mylib.so, and assuming the current working directory
handle1 = dlopen("../mylibs/mylib.so", RTLD_LAZY);
handle2 = dlopen("/usr/home/me/mylibs/mylib.so", RTLD_LAZY);
results in mylibs.so being loaded twice for the current process. On the
other hand, given the same object and current working directory, if
handle1 = dlopen("mylib.so", RTLD_LAZY);
handle2 = dlopen("/usr/home/me/mylibs/mylib.so", RTLD_LAZY);
results in mylibs.so being loaded only once. Users who wish to gain
access to the symbol table of the a.out itself using dlsym(0, mode)
should be aware that some symbols defined in the a.out may not be
available to the dynamic linker. The symbol table created by ld for use
by the dynamic linker might contain only a subset of the symbols defined
in the a.out: specifically those referenced by the shared objects with
which the a.out is linked.
A program built non_shared (with cc -non_shared for example) cannot
usefully call dlopen(), dlsym(), dlerror(), sgidlopen_version(),
sgidladd(), or dlclose() since there is no defined mechanism for dynamic
loading in non_shared programs. The dynamic loading routines are not
included in the non_shared libc.a so attempting to use them may result in
a failure at link time. Any program built non_shared that wishes to
retain code calling the dynamic loading routines must implement its own
versions of dlopen, dlsym(3), etc. and simply return appropriate error
values to avoid the link-time errors. (Building programs non_shared is
not generally recommended. Not all libraries are available non_shared.)
Use of dlclose on a DSO can cause surprising side effects because dlclose
forces many symbol GOT entries to be reset for re-lazy-evaluation. A
result of this is that previously-saved (by the application or some
library) function pointers may hold values that could be obsolete or no
longer correct. This is a problem for any dlclose but is more serious
(can cause more surprises) when dlcloseing a handle on a globally-visible
Symbol lookups proceed in order on a linear list, and a DSO is not opened
twice with the same version number (unless different dlopen paths make
the DSO name appear different to rld). When multiple sgidladds are done
and an earlier DSO is dlclosed this can change what symbol a call is
resolved to. See "NAMESPACE ISSUES" above.
PPPPaaaaggggeeee 6666 [ Back ]