DLOPEN(3C)DLOPEN(3C)


NAME
     dlopen, sgidlopen_version - Opens a Dynamic Shared Object (DSO)

SYNOPSIS
     cc [options ...] file ... -lc [library ...]

     #include <dlfcn.h>       (Required for both dlopen and for
                              sgidlopen_version)

     #include <elf.h>         (Required for sgidlopen_version only)

     void *dlopen(const char *pathname, int mode1 [ | mode2 ]);

     void *sgidlopen_version(const char *pathname, int mode1 [ | mode2 ],
          const char *version, int flags);

DESCRIPTION
     dlopen and sgidlopen_version belong to a family of routines that
     provides direct access to the dynamic linking facilities.  These
     routines are available in a library that is loaded if the -lc option
     is used with the CC(1), cc(1), f90(1), f77(1), or ld(1) command lines.

     dlopen makes a shared object available to a running process.  It
     returns a handle to the process, which the process can use on
     subsequent calls to dlsym(3C) and dlclose(3C).  This handle should not
     be interpreted in any way by the process.

     sgidlopen_version dynamically loads DSOs in a way similar to dlopen.
     However, unlike dlopen, the interface version of the DSO is specified
     (on the version and flags arguments) so that the dynamic linker tries
     to map in the DSO with the matching interface version.  Aside from the
     restriction to a particular DSO version, the effect of
     sgidlopen_version is identical to that of dlopen.

     These routines accept the following arguments:

     pathname  Specifies the path name of the object to be opened.  It can
               be an absolute path or it can be relative to the current
               directory.  If the value of pathname is 0, dlopen makes the
               symbols contained in the original a.out file, and all of the
               objects that were loaded at program startup with the a.out
               file, available through dlsym(3C).

     mode1     Specifies when relocations can occur.  This is the primary
               mode.

               When a DSO is brought into the address space of a process,
               it might 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.  mode1
               governs when these relocations occur.

               Specify either RTLD_LAZY or RTLD_NOW for mode1, as follows:

               mode1          Argument

               RTLD_LAZY      Specifies that 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 because a process
                              cannot reference all of the functions in any
                              given shared object.

               RTLD_NOW       Specifies that all necessary relocations are
                              performed when the object is first loaded.
                              This might result in some wasted effort if
                              relocations are performed for functions that
                              are never referenced, but it is useful for
                              programs that need to know as soon as an
                              object is loaded that all symbols referenced
                              during execution are available.

     mode2     Refines the mode1 specification.  This is the secondary
               mode.  You must include a mode1 specification in order to
               specify a mode2.  The mode2 argument must be preceded by an
               OR bar (|).

               Specify either RTLD_GLOBAL or RTLD_LOCAL for mode2.  If
               mode2 is not specified, RTLD_LOCAL is assumed.  The mode2
               specifications are as follows:

               mode2          Argument

               RTLD_GLOBAL    Modifies the treatment of the symbols in the
                              DSO being opened to be identical to those of
                              sgidladd(3C).  With RTLD_GLOBAL, the returned
                              handle is less necessary than without
                              RTLD_GLOBAL because rld(5) directly resolves
                              references to symbols when RTLD_GLOBAL is
                              specified and dlsym(3C) is not needed.

               RTLD_LOCAL     Specifies that symbols in the DSO are not
                              made globally visible.  Default.

               For more information on the effects of RTLD_GLOBAL and
               RTLD_LOCAL, see the "NAMESPACE ISSUES" and "SYMBOL
               VISIBILITY" sections of this man page.

     version   Specify a string that identifies the software version
               number.  For more information on version strings, see the
               ld(1) man page and the How are multiple versions of DSOs
               supported? question on the dso(5) man page.

               The version should be a single version, such as sgi2.0.
               Multiple versions are not accepted, meaning sgi2.0:sgi2.1 is
               incorrect as a value of the version string.

               While the effect of passing multiple versions in the string
               is undefined, the effect has been to treat sgi2.0:sgi2.1 as
               if it were sgi2.0, unless LL_REQUIRE_MINOR was set in the
               flags argument.  If multiple versions are in the version
               argument, and LL_REQUIRE_MINOR is in the flags argument,
               version matching fails.

     flags     Specify either LL_NONE or LL_REQUIRE_MINOR.

               Specifying LL_NONE means that the exact version must be
               present, but the minor version number is ignored in
               comparisons.

               Specifying LL_REQUIRE_MINOR means that only that precise
               major and minor version are accepted.

   NAMESPACE ISSUES
     This section does not address symbol resolution from dlsym(3C).  For
     details on its symbol resolution rules, see the dlsym(3C) man page.

     Name resolution can become surprisingly complicated and nonintuitive
     in the presence of programs or DSOs that use dlopen, sgidladd(3C),
     sgidlopen_version, or LL_DELAY_LOAD (the -delay_load option to the
     ld(1) command).

     If there is only one definition of a symbol across all loaded DSOs,
     that definition is used if it is visible.  For more information on
     visibility, see the "SYMBOL VISIBILITY" section of this man page.

     Name searches are done in the order of a single list, called 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.  If there is a later occurrence of a DSO,
     the earlier occurrence is used.  For an exception, see the "NOTES"
     section of this man page.  For any DSO library list entry marked
     LL_DELAY_LOAD, the referenced DSO is not loaded at program startup.

     An exception to the name search rule is made if a DSO is marked as
     DT_SYMBOLIC.  In this case, all name searches from within that DSO
     begin at the DSO itself and continue with the standard rld-list
     search.  For more information on this, see the -Bsymbolic option to
     the ld(1) command.

     When, as a result of a call to a function in a DSO that has been
     loaded by using LL_DELAY_LOAD, that DSO is loaded and 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 DSOs that are not
     delay-loaded are added recursively (breadth-first).  Depending on the
     order of calls to delay-loaded DSOs, the order of DSOs on the rld-list
     might be different from one run of a program to the next.

     The order of DSOs in the rld-list might 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 in rld-list order,
     the symbol that is found can be surprising.  Consider a symbol A found
     in DSOs B and C.  Further, DSO B is before DSO C in E's library list
     while DSO B is after DSO C in F's library list.  Neither DSO B nor DSO
     C are otherwise referenced.  If DSO E is opened by using dlopen with a
     mode of RTLD_GLOBAL and it is opened before DSO F, the A from DSO B is
     found by dlsym(3C) from either handle.  Similarly, if DSO F is opened
     by using dlopen with a mode of RTLD_GLOBAL and it is opened before DSO
     E, the A from DSO C is found by dlsym(3C) from either handle.
     However, if only one of the DSOs E or F is opened by using dlopen with
     a mode of RTLD_GLOBAL, 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(3C) does not cause any reordering of the rld-list.
     When the last handle (direct or indirect) on a DSO is closed with
     dlclose(3C), the DSO is removed from the rld-list.  Before the final
     dlclose(3C), the DSO remains where it was on the rld-list.

SYMBOL VISIBILITY
     DSOs loaded by a single invocation of dlopen can import symbols from
     one another or from any DSO that is globally visible, but DSOs loaded
     by one dlopen invocation cannot directly reference symbols from DSOs
     loaded by a different dlopen invocation.  You can reference those
     symbols indirectly, however, by using dlsym(3C).

     Globally visible DSOs are those added at program startup or via
     delay-load from a globally-visible object.  In addition, any DSO added
     by sgidladd(3C), by dlopen with a mode of RTLD_GLOBAL, or by
     sgidlopen_version with a mode of RTLD_GLOBAL is globally visible.
     DSOs opened with RTLD_LOCAL are not 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; for an
     example of this see the ld(1) man page's descriptions for the
     -hidden_symbol or -hides_file options.  From within a DSO, all symbols
     in that DSO are visible.  From within a DSO, all globally visible
     symbols are visible.

     Consider the following 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

     Consider the following conditions:

     * A program contains dlopen("E.so",RTLD_LAZY) and
       dlopen("H.so",RTLD_LAZY).

     * The program uses dlsym to find functions through the two handles and
       calls these two functions.

     * Each of these calls a function that calls ff() in F.so.

     * ff() calls fg(), which is defined only in G.so.

     Logically, you could assume that the call through the function
     accessed via E.so would resolve to fg() in G.so and that the call
     through the function accessed via H.so would result in an undefined
     function.  However, rld(5) 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(5) 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 through the handle in E.so.  It is unwise to
     depend on such behavior.

SEARCHING FOR DSOs
     If other DSOs were link edited with pathname when pathname was built,
     those objects are automatically loaded by dlopen.  This is 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(5).  In particular, pathname is searched for in
     the following locations:

     * The directory specified by pathname if it is not a simple file name
       (that is, it contains a slash (/) character).  If it is not a simple
       file, pathname is the only location searched; the other locations
       are ignored.

     * Any path specified via the -rpath argument to ld(1) when the
       executable file was statically linked.

     * Any directory specified by the LD_LIBRARY_PATH environment variable.
       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 LD_LIBRARY64_PATH variable, and if it is
       not set, they examine the LD_LIBRARY_PATH variable.  New 32-bit ABI
       programs examine the LD_LIBRARYN32_PATH variable and if it is not
       set, they examine the LD_LIBRARY_PATH variable.

       All of these variables are ignored if the process is running setuid
       or setgid (see exec(2)).

     * The default search paths.  The paths differ depending on ABI.  For
       information on the specific search paths, see the rld(5) man page.

     If the process is running setuid or setgid, the _RLD_ROOT,
     _RLDN32_ROOT, or _RLD64_ROOT variable (the exact variable name depends
     on the ABI being used) is ignored (see rld(5)).

NOTES
     You can open objects whose names resolve to the same absolute or
     relative path name any number of times by using dlopen.  However, the
     referenced object is loaded only once into the address space of the
     current process.  The same object referenced by two different path
     names, however, can be loaded multiple times.  For example, given the
     object /usr/home/me/mylibs/mylib.so, and assuming the current working
     directory is /usr/home/me/workdir, the following code results in
     mylibs.so being loaded twice for the current process:

          ...
          void *handle1;
          void *handle2;

          handle1 = dlopen("../mylibs/mylib.so", RTLD_LAZY);
          handle2 = dlopen("/usr/home/me/mylibs/mylib.so", RTLD_LAZY);
          ...

     Given the same object and current working directory, if
     LD_LIBRARY_PATH=/usr/home/me/mylibs, the following code results in
     mylibs.so being loaded only once:

          ...
          void *handle1;
          void *handle2;

          handle1 = dlopen("mylib.so", RTLD_LAZY);
          handle2 = dlopen("/usr/home/me/mylibs/mylib.so", RTLD_LAZY);
          ...

     Users who use dlsym(0,mode) to gain access to the symbol table of the
     a.out file itself should be aware that some symbols defined in the
     a.out file might not be available to the dynamic linker.  The symbol
     table created by ld(1) for use by the dynamic linker might contain
     only a subset of the symbols defined in the a.out file, specifically
     those referenced by the shared objects with which the a.out file is
     linked.

     Because there is no defined mechanism for dynamic loading in nonshared
     programs, a program built as nonshared (for example, by using cc
     -non_shared) cannot usefully call dlopen, dlsym(3C), dlerror(3C),
     sgidlopen_version, sgidladd(3C), or dlclose(3C).  The dynamic loading
     routines are not included in the nonshared libc.a file, so attempting
     to use them might result in a failure at link time.  Any program built
     as nonshared that wishes to retain code that calls the dynamic loading
     routines must implement its own versions of dlopen, dlsym(3C), and so
     on, and simply return appropriate error values to avoid the link-time
     errors.  Note that building programs as nonshared is not generally
     recommended because not all libraries are available as nonshared.

     Using dlclose(3C) on a DSO, with _RLD_ARGS set to -s in the
     environment, can cause surprising side effects.  This is because
     dlclose(3C) forces many symbol GOT entries to be reset for
     re-lazy-evaluation.  A result of this is that function pointers
     previously saved by the application or some library might hold values
     that could be obsolete or no longer correct.  This is a problem for
     any dlclose(3C) process, but it is more serious when dlclose(3C) is
     used to close a handle on a globally-visible DSO.

     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(5)).  When multiple
     sgidladd(3C) processes are executed and dlclose(3C) is used to close
     an earlier DSO, this can change the symbol to which a call is
     resolved.  For more information, see the "NAMESPACE ISSUES" section.

EXAMPLES
     The following specifies the RTLD_LAZY and RTLD_LOCAL modes:

          dlopen("X.so",RTLD_LAZY|RTLD_LOCAL);

     The following example program uses dlopen and was compiled with the
     -32 compiler command line option:

          dltry.c:
          -------
          /* Error handling code not shown.
          */
          #include <dlfcn.h>

          typedef int (*xamplefuncptr)(int);
          int main()
          {
             void *handle;
             int   i;
             xamplefuncptr fptr;

             handle = dlopen("greetings.so", RTLD_LAZY|RTLD_LOCAL);
             fptr = (xamplefuncptr)dlsym(handle, "greetings");
             i = (*fptr)(3);
             return 0;
          }

          greetings.c:
          -----------
          #include <stdio.h>
          int greetings(int num_greetings)
          {
             int i;

             for (i=0; i < num_greetings; i++)
                printf ("hello world\n");
             return 1;
          }


          % cc -32 -c dltry.c greetings.c
          % ld -32 -shared greetings.o -soname greetings.so -o greetings.so
          % cc -32 dltry.o
          % LD_LIBRARY_PATH=.
          % export LD_LIBRARY_PATH
          % a.out
          hello world
          hello world
          hello world

RETURN VALUES
     If pathname cannot be found, cannot be opened for reading, is not a
     DSO, 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(3C).

SEE ALSO
     CC(1), cc(1), f77(1), f90(1), ld(1), sh(1)

     exec(2)

     dlclose(3C), dlerror(3C), dlsym(3C), sgidladd(3C),

     dso(5), rld(5)