man-pages/man3/dlopen.3

594 lines
17 KiB
Groff

.\" Copyright 1995 Yggdrasil Computing, Incorporated.
.\" written by Adam J. Richter (adam@yggdrasil.com),
.\" with typesetting help from Daniel Quinlan (quinlan@yggdrasil.com).
.\" and Copyright 2003, 2015 Michael Kerrisk (mtk.manpages@gmail.com).
.\"
.\" %%%LICENSE_START(GPLv2+_DOC_FULL)
.\" This is free documentation; you can redistribute it and/or
.\" modify it under the terms of the GNU General Public License as
.\" published by the Free Software Foundation; either version 2 of
.\" the License, or (at your option) any later version.
.\"
.\" The GNU General Public License's references to "object code"
.\" and "executables" are to be interpreted as the output of any
.\" document formatting or typesetting system, including
.\" intermediate and printed output.
.\"
.\" This manual is distributed in the hope that it will be useful,
.\" but WITHOUT ANY WARRANTY; without even the implied warranty of
.\" MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
.\" GNU General Public License for more details.
.\"
.\" You should have received a copy of the GNU General Public
.\" License along with this manual; if not, see
.\" <http://www.gnu.org/licenses/>.
.\" %%%LICENSE_END
.\"
.\" Modified by David A. Wheeler <dwheeler@dwheeler.com> 2000-11-28.
.\" Applied patch by Terran Melconian, aeb, 2001-12-14.
.\" Modified by Hacksaw <hacksaw@hacksaw.org> 2003-03-13.
.\" Modified by Matt Domsch, 2003-04-09: _init and _fini obsolete
.\" Modified by Michael Kerrisk <mtk.manpages@gmail.com> 2003-05-16.
.\" Modified by Walter Harms: dladdr, dlvsym
.\" Modified by Petr Baudis <pasky@suse.cz>, 2008-12-04: dladdr caveat
.\"
.TH DLOPEN 3 2015-03-29 "Linux" "Linux Programmer's Manual"
.SH NAME
dlclose, dlerror, dlopen, dlmopen, dlsym, dlvsym \-
programming interface to dynamic linking loader
.SH SYNOPSIS
.B #include <dlfcn.h>
.sp
.BI "void *dlopen(const char *" filename ", int " flags );
.sp
.B "char *dlerror(void);"
.sp
.BI "void *dlsym(void *" handle ", const char *" symbol );
.sp
.BI "int dlclose(void *" handle );
.sp
.B #define _GNU_SOURCE
.br
.B #include <dlfcn.h>
.sp
.BI "void *dlmopen (Lmid_t " lmid ", const char *" filename ", int " flags );
.sp
.BI "void *dlvsym(void *" handle ", char *" symbol ", char *" version );
.sp
Link with \fI\-ldl\fP.
.SH DESCRIPTION
The functions described in this page
provide an interface to the dynamic linking loader.
.SS dlerror()
The function
.BR dlerror ()
returns a human-readable string describing the most recent error
that occurred from
.BR dlopen (),
.BR dlsym ()
.BR dlvsym (),
or
.BR dlclose ()
since the last call to
.BR dlerror ().
It returns NULL if no errors have occurred since initialization or since
it was last called.
.SS dlopen()
The function
.BR dlopen ()
loads the dynamic shared object (shared library)
file named by the null-terminated
string
.I filename
and returns an opaque "handle" for the loaded object.
If
.I filename
is NULL, then the returned handle is for the main program.
If
.I filename
contains a slash ("/"), then it is interpreted as a (relative
or absolute) pathname.
Otherwise, the dynamic linker searches for the object as follows
(see
.BR ld.so (8)
for further details):
.IP o 4
(ELF only) If the executable file for the calling program
contains a DT_RPATH tag, and does not contain a DT_RUNPATH tag,
then the directories listed in the DT_RPATH tag are searched.
.IP o
If, at the time that the program was started, the environment variable
.B LD_LIBRARY_PATH
was defined to contain a colon-separated list of directories,
then these are searched.
(As a security measure, this variable is ignored for set-user-ID and
set-group-ID programs.)
.IP o
(ELF only) If the executable file for the calling program
contains a DT_RUNPATH tag, then the directories listed in that tag
are searched.
.IP o
The cache file
.I /etc/ld.so.cache
(maintained by
.BR ldconfig (8))
is checked to see whether it contains an entry for
.IR filename .
.IP o
The directories
.I /lib
and
.I /usr/lib
are searched (in that order).
.PP
If the object specified by
.I filename
has dependencies on other shared objects,
then these are also automatically loaded by the dynamic linker
using the same rules.
(This process may occur recursively,
if those objects in turn have dependencies, and so on.)
.PP
One of the following two values must be included in
.IR flags :
.TP
.B RTLD_LAZY
Perform lazy binding.
Only resolve symbols as the code that references them is executed.
If the symbol is never referenced, then it is never resolved.
(Lazy binding is performed only for function references;
references to variables are always immediately bound when
the shared object is loaded.)
.TP
.B RTLD_NOW
If this value is specified, or the environment variable
.B LD_BIND_NOW
is set to a nonempty string,
all undefined symbols in the shared object are resolved before
.BR dlopen ()
returns.
If this cannot be done, an error is returned.
.PP
Zero or more of the following values may also be ORed in
.IR flags :
.TP
.B RTLD_GLOBAL
The symbols defined by this shared object will be
made available for symbol resolution of subsequently loaded shared object.
.TP
.B RTLD_LOCAL
This is the converse of
.BR RTLD_GLOBAL ,
and the default if neither flag is specified.
Symbols defined in this shared object are not made available to resolve
references in subsequently loaded shared objects.
.TP
.BR RTLD_NODELETE " (since glibc 2.2)"
Do not unload the shared object during
.BR dlclose ().
Consequently, the object's static variables are not reinitialized
if the object is reloaded with
.BR dlopen ()
at a later time.
This flag is not specified in POSIX.1-2001.
.\" (But it is present on Solaris.)
.TP
.BR RTLD_NOLOAD " (since glibc 2.2)"
Don't load the shared object.
This can be used to test if the object is already resident
.RB ( dlopen ()
returns NULL if it is not, or the object's handle if it is resident).
This flag can also be used to promote the flags on a shared object
that is already loaded.
For example, a shared object that was previously loaded with
.B RTLD_LOCAL
can be reopened with
.BR RTLD_NOLOAD\ |\ RTLD_GLOBAL .
This flag is not specified in POSIX.1-2001.
.\" (But it is present on Solaris.)
.\"
.TP
.BR RTLD_DEEPBIND " (since glibc 2.3.4)"
.\" Inimitably described by UD in
.\" http://sources.redhat.com/ml/libc-hacker/2004-09/msg00083.html.
Place the lookup scope of the symbols in this
shared object ahead of the global scope.
This means that a self-contained object will use
its own symbols in preference to global symbols with the same name
contained in objects that have already been loaded.
This flag is not specified in POSIX.1-2001.
.PP
If
.I filename
is NULL, then the returned handle is for the main program.
When given to
.BR dlsym (),
this handle causes a search for a symbol in the main program,
followed by all shared objects loaded at program startup,
and then all shared objects loaded by
.BR dlopen ()
with the flag
.BR RTLD_GLOBAL .
.PP
External references in the shared object are resolved using the
shared objects in that object's dependency list and any other
objects previously opened with the
.B RTLD_GLOBAL
flag.
If the executable was linked with the flag "\-rdynamic"
(or, synonymously, "\-\-export\-dynamic"),
then the global symbols in the executable will also be used
to resolve references in a dynamically loaded shared object.
.PP
If the same shared object is loaded again with
.BR dlopen (),
the same object handle is returned.
The dl library maintains reference
counts for object handles, so a dynamically loaded shared object is not
deallocated until
.BR dlclose ()
has been called on it as many times as
.BR dlopen ()
has succeeded on it.
The
.BR _init ()
routine, if present, is called only once.
But a subsequent call with
.B RTLD_NOW
may force symbol resolution for a shared object earlier loaded with
.BR RTLD_LAZY .
.PP
If
.BR dlopen ()
fails for any reason, it returns NULL.
.\"
.SS dlmopen()
This function performs the same task as
.BR dlopen ()\(emthe
.I filename
and
.I flags
arguments, as well as the return value, are the same.
It differs in that it accepts an additional argument,
.IR lmid ,
that specifies the link-map list (also referred to as a
.IR namespace )
in which the shared object should be loaded.
(By comparison,
.BR dlopen ()
adds the dynamically loaded shared object to the same namespace as
the shared object from which the
.BR dlopen ()
call is made.)
The
.I Lmid_t
type is an opaque handle that refers to a namespace.
The
.I lmid
argument is either the ID of an existing namespace
.\" FIXME: Is using dlinfo() RTLD_DI_LMID the right technique?
(which can be obtained using the
.BR dlinfo (3)
.B RTLD_DI_LMID
request) or one of the following special values:
.TP
.B LM_ID_BASE
Load the shared object in the initial namespace
(i.e., the application's namespace).
.TP
.B LM_ID_NEWLM
Create a new namespace and load the shared object in that namespace.
The object must have been correctly
(statically) linked
to reference all of the other shared objects that it requires,
since the new namespace is initially empty.
The glibc implementation supports a maximum of
.\" DL_NNS
16 namespaces.
.\"
.SS dlsym()
The function
.BR dlsym ()
takes a "handle" of a dynamic loaded shared object returned by
.BR dlopen ()
and the
null-terminated symbol name, returning the address where that symbol is
loaded into memory.
If the symbol is not found, in the specified
object or any of the shared objects that were automatically loaded by
.BR dlopen ()
when that object was loaded,
.BR dlsym ()
returns NULL.
(The search performed by
.BR dlsym ()
is breadth first through the dependency tree of these shared objects.)
Since the value of the symbol could actually be NULL (so that a
NULL return from
.BR dlsym ()
need not indicate an error), the correct way to test for an error
is to call
.BR dlerror ()
to clear any old error conditions, then call
.BR dlsym (),
and then call
.BR dlerror ()
again, saving its return value into a variable, and check whether
this saved value is not NULL.
.PP
There are two special pseudo-handles:
.TP
.B RTLD_DEFAULT
Find the first occurrence of the desired symbol
using the default shared object search order.
The search will include global symbols in the executable
and its dependencies,
as well as symbols in shared objects that were dynamically loaded with the
.BR RTLD_GLOBAL
flag.
.TP
.BR RTLD_NEXT
Find the next occurrence of the desired symbol in the search order
after the current object.
This allows one to provide a wrapper
around a function in another shared object, so that, for example,
the definition of a function in a preloaded shared object
(see
.B LD_PRELOAD
in
.BR ld.so (8))
can find and invoke the "real" function provided in another shared object
(or for that matter, the "next" definition of the function in cases
where there are multiple layers of preloading).
.SS dlvsym()
The function
.BR dlvsym ()
does the same as
.BR dlsym ()
but takes a version string as an additional argument.
.SS dlclose()
The function
.BR dlclose ()
decrements the reference count on the
dynamically loaded shared object referred to by
.IR handle .
If the reference count drops to zero,
then the object is unloaded.
All shared objects that were automatically loaded when
.BR dlopen ()
was invoked on the object referred to by
.I handle
are recursively closed in the same manner.
.LP
The function
.BR dlclose ()
returns 0 on success, and nonzero on error.
.SS The obsolete symbols _init() and _fini()
The linker recognizes special symbols
.B _init
and
.BR _fini .
If a dynamically loaded shared object exports a routine named
.BR _init (),
then that code is executed after the loading, before
.BR dlopen ()
returns.
If the shared object exports a routine named
.BR _fini (),
then that routine is called just before the object is unloaded.
In case you need to avoid linking against the system startup files,
this can be done by using the
.BR gcc (1)
.I \-nostartfiles
command-line option.
.LP
Using these routines, or the gcc
.B \-nostartfiles
or
.B \-nostdlib
options, is not recommended.
Their use may result in undesired behavior,
since the constructor/destructor routines will not be executed
(unless special measures are taken).
.\" void _init(void) __attribute__((constructor));
.\" void _fini(void) __attribute__((destructor));
.LP
Instead, shared objects should export routines using the
.B __attribute__((constructor))
and
.B __attribute__((destructor))
function attributes.
See the gcc info pages for information on these.
Constructor routines are executed before
.BR dlopen ()
returns, and destructor routines are executed before
.BR dlclose ()
returns.
.SH VERSIONS
.BR dlopen (),
.BR dlsym (),
.BR dlclose (),
and
.BR dlerror ()
are present in glibc 2.0 and later.
.BR dlmopen ()
first appeared in glibc 2.3.4.
.BR dlvsym ()
first appeared in glibc 2.1.
.SH CONFORMING TO
POSIX.1-2001 describes
.BR dlclose (),
.BR dlerror (),
.BR dlopen (),
and
.BR dlsym ().
The
.BR dlmopen ()
and
.BR dlvsym ()
functions are GNU extensions.
.SH NOTES
The symbols
.B RTLD_DEFAULT
and
.B RTLD_NEXT
are defined by
.I <dlfcn.h>
only when
.B _GNU_SOURCE
was defined before including it.
.\" .LP
.\" The string returned by
.\" .BR dlerror ()
.\" should not be modified.
.\" Some systems give the prototype as
.\" .sp
.\" .in +5
.\" .B "const char *dlerror(void);"
.\" .in
Since glibc 2.2.3,
.BR atexit (3)
can be used to register an exit handler that is automatically
called when a shared object is unloaded.
.\"
.SS dlmopen() and namespaces
A link-map list defines an isolated namespace for the
resolution of symbols by the dynamic linker.
Within a namespace,
dependent shared objects are implicitly loaded according to the usual rules,
and symbol references are likewise resolved according to the usual rules,
but such resolution is confined to the definitions provided by the
objects that have been (explicitly and implicitly) loaded into the namespace.
The
.BR dlmopen ()
function permits object-load isolation\(emthe ability
to load a shared object in a new namespace without
exposing the rest of the application to the symbols
made available by the new object.
Note that the use of the
.B RTLD_LOCAL
flag is not sufficient for this purpose,
since it prevents a shared object's symbols from being available to
.I any
other shared object.
In some cases,
we may want to make the symbols provided by a dynamically
loaded shared object available to (a subset of) other shared objects
without exposing those symbols to the entire application.
This can be achieved by using a separate namespace and the
.B RTLD_GLOBAL
flag.
Possible uses of
.BR dlmopen ()
are plugins where the author of the plugin-loading framework
can't trust the plugin authors and does not wish
any undefined symbols from the plugin framework to be resolved to plugin
symbols.
Another use is to load the same object more than once.
Without the use of
.BR dlopen (),
this would require the creation of distinct copies of the shared object file.
Using
.BR dlopen (),
this can be achieved by loading the same shared object file into
different namespaces.
.\"
.SS History
The dlopen interface standard comes from SunOS.
That system does not have
.BR dlvsym (),
but does have
.BR dlmopen ().
.SH EXAMPLE
Load the math library, and print the cosine of 2.0:
.nf
#include <stdio.h>
#include <stdlib.h>
#include <dlfcn.h>
int
main(int argc, char **argv)
{
void *handle;
double (*cosine)(double);
char *error;
handle = dlopen("libm.so", RTLD_LAZY);
if (!handle) {
fprintf(stderr, "%s\en", dlerror());
exit(EXIT_FAILURE);
}
dlerror(); /* Clear any existing error */
cosine = (double (*)(double)) dlsym(handle, "cos");
/* According to the ISO C standard, casting between function
pointers and 'void *', as done above, produces undefined results.
POSIX.1-2003 and POSIX.1-2008 accepted this state of affairs and
proposed the following workaround:
*(void **) (&cosine) = dlsym(handle, "cos");
This (clumsy) cast conforms with the ISO C standard and will
avoid any compiler warnings.
The 2013 Technical Corrigendum to POSIX.1-2008 (a.k.a.
POSIX.1-2013) improved matters by requiring that conforming
implementations support casting 'void *' to a function pointer.
Nevertheless, some compilers (e.g., gcc with the '-pedantic'
option) may complain about the cast used in this program. */
.\" http://pubs.opengroup.org/onlinepubs/009695399/functions/dlsym.html#tag_03_112_08
.\" http://pubs.opengroup.org/onlinepubs/9699919799/functions/dlsym.html#tag_16_96_07
.\" http://austingroupbugs.net/view.php?id=74
error = dlerror();
if (error != NULL) {
fprintf(stderr, "%s\en", error);
exit(EXIT_FAILURE);
}
printf("%f\en", (*cosine)(2.0));
dlclose(handle);
exit(EXIT_SUCCESS);
}
.fi
.PP
If this program were in a file named "foo.c", you would build the program
with the following command:
.in +4n
.LP
gcc \-rdynamic \-o foo foo.c \-ldl
.in
.PP
Shared objects exporting (the obsolete)
.BR _init ()
and
.BR _fini ()
will want to be compiled as
follows, using
.I bar.c
as the example name:
.in +4n
.LP
gcc \-shared \-nostartfiles \-o bar bar.c
.in
.SH SEE ALSO
.BR ld (1),
.BR ldd (1),
.BR pldd (1),
.BR dl_iterate_phdr (3),
.BR dladdr (3),
.BR dlinfo (3),
.BR rtld-audit (7),
.BR ld.so (8),
.BR ldconfig (8)
ld.so info pages, gcc info pages, ld info pages