]> git.ipfire.org Git - thirdparty/man-pages.git/blobdiff - man3/dlopen.3
dlopen.3: wfix: consistently use "object" rather than "library"
[thirdparty/man-pages.git] / man3 / dlopen.3
index 77451cc59236987b40ec653c69ce65655426101a..885667470dd3fd0ca68f7195cf42af9ea38449a5 100644 (file)
@@ -1,7 +1,7 @@
 .\" 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 Michael Kerrisk (mtk.manpages@gmail.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
 .\" 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"
+.TH DLOPEN 3 2017-09-15 "Linux" "Linux Programmer's Manual"
 .SH NAME
-dlclose, dlerror, dlopen, dlsym, dlvsym \-
-programming interface to dynamic linking loader
+dlclose, dlopen, dlmopen \-
+open and close a shared object
 .SH SYNOPSIS
 .B #include <dlfcn.h>
-.sp
+.PP
 .BI "void *dlopen(const char *" filename ", int " flags );
-.sp
-.B "char *dlerror(void);"
-.sp
-.BI "void *dlsym(void *" handle ", const char *" symbol );
-.sp
+.PP
 .BI "int dlclose(void *" handle );
-.sp
+.PP
+.B #define _GNU_SOURCE
+.br
+.B #include <dlfcn.h>
+.PP
+.BI "void *dlmopen (Lmid_t " lmid ", const char *" filename ", int " flags );
+.PP
 Link with \fI\-ldl\fP.
 .SH DESCRIPTION
-The four functions
-.BR dlopen (),
-.BR dlsym (),
-.BR dlclose (),
-.BR dlerror ()
-provide an interface to the dynamic linking loader.
-Some additional nonstandard extensions to this API are documented below.
-.SS dlerror()
-The function
-.BR dlerror ()
-returns a human-readable string describing the most recent error
-that occurred from
-.BR dlopen (),
-.BR dlsym ()
-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 library file named by the null-terminated
+loads the dynamic shared object (shared library)
+file named by the null-terminated
 string
 .I filename
-and returns an opaque "handle" for the dynamic library.
+and returns an opaque "handle" for the loaded object.
+This handle is employed with other functions in the dlopen API, such as
+.BR dlsym (3),
+.BR dladdr (3),
+.BR dlinfo (3),
+and
+.BR dlclose ().
+.PP
 If
 .I filename
+.\" FIXME On Solaris, when handle is NULL, we seem to get back
+.\" a handle for (something like) the root of the namespace.
+.\" The point here is that if we do a dlmopen(LM_ID_NEWLM), then
+.\" the filename==NULL case returns a different handle than
+.\" in the initial namespace. But, on glibc, the same handle is
+.\" returned. This is probably a bug in glibc.
+.\"
 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 library as follows
+Otherwise, the dynamic linker searches for the object as follows
 (see
 .BR ld.so (8)
 for further details):
@@ -116,28 +113,35 @@ and
 .I /usr/lib
 are searched (in that order).
 .PP
-If the library has dependencies on other shared libraries,
+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 libraries in turn have dependencies, and so on.)
+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.
+Resolve symbols only 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 library is loaded.)
+the shared object is loaded.)
+Since glibc 2.1.1,
+.\" commit 12b5b6b7f78ea111e89bbf638294a5413c791072
+this flag is overridden by the effect of the
+.B LD_BIND_NOW
+environment variable.
 .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 library are resolved before
+all undefined symbols in the shared object are resolved before
 .BR dlopen ()
 returns.
 If this cannot be done, an error is returned.
@@ -146,50 +150,45 @@ Zero or more of the following values may also be ORed in
 .IR flags :
 .TP
 .B RTLD_GLOBAL
-The symbols defined by this library will be
-made available for symbol resolution of subsequently loaded libraries.
+The symbols defined by this shared object will be
+made available for symbol resolution of subsequently loaded shared objects.
 .TP
 .B RTLD_LOCAL
 This is the converse of
 .BR RTLD_GLOBAL ,
 and the default if neither flag is specified.
-Symbols defined in this library are not made available to resolve
-references in subsequently loaded libraries.
+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 library during
+Do not unload the shared object during
 .BR dlclose ().
-Consequently, the library's static variables are not reinitialized
-if the library is reloaded with
+Consequently, the object's static and global 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 library.
-This can be used to test if the library is already resident
+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 library's handle if it is resident).
-This flag can also be used to promote the flags on a library
+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 library that was previously loaded with
+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
-library ahead of the global scope.
-This means that a self-contained library will use
+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 libraries that have already been loaded.
-This flag is not specified in POSIX.1-2001.
+contained in objects that have already been loaded.
 .PP
 If
 .I filename
@@ -197,231 +196,383 @@ 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 libraries loaded at program startup,
-and then all shared libraries loaded by
+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 library are resolved using the libraries
-in that library's dependency list and any other libraries 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 library.
+Symbol references in the shared object are resolved using (in order):
+symbols in the link map of objects loaded for the main program and its
+dependencies;
+symbols in shared objects (and their dependencies)
+that were previously opened with
+.BR dlopen ()
+using the
+.BR RTLD_GLOBAL
+flag;
+and definitions in the shared object itself
+(and any dependencies that were loaded for that object).
 .PP
-If the same library is loaded again with
+Any global symbols in the executable that were placed into
+its dynamic symbol table by
+.BR ld (1)
+can also be used to resolve references in a dynamically loaded shared object.
+Symbols may be placed in the dynamic symbol table
+either because the executable was linked with the flag "\-rdynamic"
+(or, synonymously, "\-\-export\-dynamic"), which causes all of
+the executable's global symbols to be placed in the dynamic symbol table,
+or because
+.BR ld (1)
+noted a dependency on a symbol in another object during static linking.
+.PP
+If the same shared object is opened again with
 .BR dlopen (),
-the same library handle is returned.
-The dl library maintains reference
-counts for library handles, so a dynamic library is not
+the same object handle is returned.
+The dynamic linker 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
+Constructors (see below) are called only when the object is actually loaded
+into memory (i.e., when the reference count increases to 1).
+.PP
+A subsequent
+.BR dlopen ()
+call that loads the same shared object with
 .B RTLD_NOW
-may force symbol resolution for a library earlier loaded with
+may force symbol resolution for a shared object earlier loaded with
 .BR RTLD_LAZY .
+Similarly, an object that was previously opened with
+.BR RTLD_LOCAL
+can be promoted to
+.BR RTLD_GLOBAL
+in a subsequent
+.BR dlopen ().
 .PP
 If
 .BR dlopen ()
 fails for any reason, it returns NULL.
-.SS dlsym()
-The function
-.BR dlsym ()
-takes a "handle" of a dynamic library returned by
+.\"
+.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,
+except for the differences noted below.
+.PP
+The
+.BR dlmopen ()
+function differs from
 .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
-library or any of the libraries that were automatically loaded by
+primarily 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 ()
-when that library was loaded,
-.BR dlsym ()
-returns NULL.
-(The search performed by
-.BR dlsym ()
-is breadth first through the dependency tree of these libraries.)
-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.
+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.
 .PP
-There are two special pseudo-handles:
+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 RTLD_DEFAULT
-Find the first occurrence of the desired symbol
-using the default library search order.
-The search will include global symbols in the executable
-and its dependencies,
-as well as symbols in libraries that were dynamically loaded with the
-.BR RTLD_GLOBAL
-flag.
+.B LM_ID_BASE
+Load the shared object in the initial namespace
+(i.e., the application's namespace).
 .TP
-.BR RTLD_NEXT
-Find the next occurrence of the desired symbol in the search order
-after the current library.
-This allows one to provide a wrapper
-around a function in another shared library, so that, for example,
-the definition of a function in a preloaded library
-(see
-.B LD_PRELOAD
-in
-.BR ld.so (8))
-can find and invoke the "real" function provided in another library
-(or for that matter, the "next" definition of the function in cases
-where there are multiple layers of preloading).
+.B LM_ID_NEWLM
+Create a new namespace and load the shared object in that namespace.
+The object must have been correctly linked
+to reference all of the other shared objects that it requires,
+since the new namespace is initially empty.
+.PP
+If
+.I filename
+is NULL, then the only permitted value for
+.I lmid
+is
+.BR LM_ID_BASE .
 .SS dlclose()
 The function
 .BR dlclose ()
-decrements the reference count on the dynamic library handle
+decrements the reference count on the
+dynamically loaded shared object referred to by
 .IR handle .
-If the reference count drops to zero,
-then the dynamic library is unloaded.
+.PP
+If the object's reference count drops to zero
+and no symbols in this object are required by other objects,
+then the object is unloaded
+after first calling any destructors defined for the object.
+(Symbols in this object might be required in another object
+because this object was opened with the
+.BR RTLD_GLOBAL
+flag and one of its symbols satisfied a relocation in another object.)
+.PP
 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
+.PP
+A successful return from
+.BR dlclose ()
+does not guarantee that the symbols associated with
+.I handle
+are removed from the caller's address space.
+In addition to references resulting from explicit
+.BR dlopen ()
+calls, a shared object may have been implicitly loaded
+(and reference counted) because of dependencies in other shared objects.
+Only when all references have been released can the shared object
+be removed from the address space.
+.SH RETURN VALUE
+On success,
+.BR dlopen ()
+and
+.BR dlmopen ()
+return a non-NULL handle for the loaded object.
+On error
+(file could not be found, was not readable, had the wrong format,
+or caused errors during loading),
+these functions return NULL.
+.PP
+On success,
+.BR dlclose ()
+returns 0; on error, it returns a nonzero value.
+.PP
+Errors from these functions can be diagnosed using
+.BR dlerror (3).
+.SH VERSIONS
+.BR dlopen ()
+and
+.BR dlclose ()
+are present in glibc 2.0 and later.
+.BR dlmopen ()
+first appeared in glibc 2.3.4.
+.SH ATTRIBUTES
+For an explanation of the terms used in this section, see
+.BR attributes (7).
+.TS
+allbox;
+lbw30 lb lb
+l l l.
+Interface      Attribute       Value
+T{
+.BR dlopen (),
+.BR dlmopen (),
+.BR dlclose ()
+T}     Thread safety   MT-Safe
+.TE
+.SH CONFORMING TO
+POSIX.1-2001 describes
+.BR dlclose ()
+and
+.BR dlopen ().
+The
+.BR dlmopen ()
+function is a GNU extension.
+.PP
+The
+.BR RTLD_NOLOAD ,
+.BR RTLD_NODELETE ,
+and
+.BR RTLD_DEEPBIND
+flags are GNU extensions;
+the first two of these flags are also present on Solaris.
+.SH NOTES
+.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.
+.PP
+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.
+.PP
+The
+.BR dlmopen ()
+function also can be used to provide better isolation than the
+.BR RTLD_LOCAL
+flag.
+In particular, shared objects loaded with
+.BR RTLD_LOCAL
+may be promoted to
+.BR RTLD_GLOBAL
+if they are dependencies of another shared object loaded with
+.BR RTLD_GLOBAL .
+Thus,
+.BR RTLD_LOCAL
+is insufficient to isolate a loaded shared object except in the (uncommon)
+case where one has explicit control over all shared object dependencies.
+.PP
+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 dlmopen (),
+this would require the creation of distinct copies of the shared object file.
+Using
+.BR dlmopen (),
+this can be achieved by loading the same shared object file into
+different namespaces.
+.PP
+The glibc implementation supports a maximum of
+.\" DL_NNS
+16 namespaces.
+.\"
+.SS Initialization and finalization functions
+Shared objects may export functions using the
+.B __attribute__((constructor))
+and
+.B __attribute__((destructor))
+function attributes.
+Constructor functions are executed before
+.BR dlopen ()
+returns, and destructor functions are executed before
 .BR dlclose ()
-returns 0 on success, and nonzero on error.
-.SS The obsolete symbols _init() and _fini()
-The linker recognizes special symbols
+returns.
+A shared object may export multiple constructors and destructors,
+and priorities can be associated with each function
+to determine the order in which they are executed.
+See the
+.BR gcc
+info pages (under "Function attributes")
+.\" info gcc "C Extensions" "Function attributes"
+for further information.
+.PP
+An older method of (partially) achieving the same result is via the use of
+two special symbols recognized by the linker:
 .B _init
 and
 .BR _fini .
-If a dynamic library exports a routine named
+If a dynamically loaded shared object exports a routine named
 .BR _init (),
-then that code is executed after the loading, before
+then that code is executed after loading a shared object, before
 .BR dlopen ()
 returns.
-If the dynamic library exports a routine named
+If the shared object exports a routine named
 .BR _fini (),
-then that routine is called just before the library is unloaded.
-In case you need to avoid linking against the system startup files,
+then that routine is called just before the object is unloaded.
+In this case, one must avoid linking against the system startup files,
+which contain default versions of these 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, libraries 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.
-.SS Glibc extension: dlvsym()
-Glibc adds the following function not described by POSIX,
-with prototype as follows:
-.sp
-.nf
-.BR "#define _GNU_SOURCE" "         /* See feature_test_macros(7) */"
-.B #include <dlfcn.h>
-.sp
-.BI "void *dlvsym(void *" handle ", char *" symbol ", char *" version );
-.fi
 .PP
-The function
-.BR dlvsym (),
-provided by glibc since version 2.1,
-does the same as
-.BR dlsym ()
-but takes a version string as an additional argument.
-.SH VERSIONS
-.BR dlopen (),
-.BR dlsym (),
-.BR dlclose (),
-and
-.BR dlerror ()
-are present in glibc 2.0 and later.
-.BR dlvsym ()
-first appeared in glibc 2.1.
-.SH CONFORMING TO
-POSIX.1-2001 describes
-.BR dlclose (),
-.BR dlerror (),
-.BR dlopen (),
-and
-.BR dlsym ().
-.SH NOTES
-The symbols
-.B RTLD_DEFAULT
+Use of
+.B _init
 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
-
+.BR _fini
+is now deprecated in favor of the aforementioned
+constructors and destructors,
+which among other advantages,
+permit multiple initialization and finalization functions to be defined.
+.\"
+.\" 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));
+.\"
+.PP
 Since glibc 2.2.3,
 .BR atexit (3)
 can be used to register an exit handler that is automatically
-called when a library is unloaded.
+called when a shared object is unloaded.
 .SS History
-The dlopen interface standard comes from SunOS.
-That system does not have
-.BR dlvsym ().
+These functions are part of the dlopen API, derived from SunOS.
+.SH BUGS
+As at glibc 2.24, specifying the
+.BR RTLD_GLOBAL
+flag when calling
+.BR dlmopen ()
+.\" dlerror(): "invalid mode"
+generates an error.
+Furthermore, specifying
+.BR RTLD_GLOBAL
+when calling
+.BR dlopen ()
+results in a program crash
+.RB ( SIGSEGV )
+if the call is made from any object loaded in a
+namespace other than the initial namespace.
 .SH EXAMPLE
-Load the math library, and print the cosine of 2.0:
-.nf
-
+The program below loads the (glibc) math library,
+looks up the address of the
+.BR cos (3)
+function, and prints the cosine of 2.0.
+The following is an example of building and running the program:
+.PP
+.in +4n
+.EX
+$ \fBcc dlopen_demo.c \-ldl\fP
+$ \fB./a.out\fP
+\-0.416147
+.EE
+.in
+.SS Program source
+\&
+.EX
 #include <stdio.h>
 #include <stdlib.h>
 #include <dlfcn.h>
-
+#include <gnu/lib-names.h>  /* Defines LIBM_SO (which will be a
+                               string such as "libm.so.6") */
 int
-main(int argc, char **argv)
+main(void)
 {
     void *handle;
     double (*cosine)(double);
     char *error;
 
-    handle = dlopen("libm.so", RTLD_LAZY);
+    handle = dlopen(LIBM_SO, RTLD_LAZY);
     if (!handle) {
         fprintf(stderr, "%s\en", dlerror());
         exit(EXIT_FAILURE);
@@ -460,34 +611,18 @@ main(int argc, char **argv)
     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
-Libraries 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
+.EE
 .SH SEE ALSO
 .BR ld (1),
 .BR ldd (1),
 .BR pldd (1),
 .BR dl_iterate_phdr (3),
+.BR dladdr (3),
+.BR dlerror (3),
+.BR dlinfo (3),
+.BR dlsym (3),
 .BR rtld-audit (7),
 .BR ld.so (8),
 .BR ldconfig (8)
-
-ld.so info pages, gcc info pages, ld info pages
+.PP
+gcc info pages, ld info pages