Search code examples
linuxshared-librariesdlopen

library path when dynamically loaded?


How can I get the path of the shared library from within the library itself?

In other words, let's say that library X is loaded using dlopen(), how can I get access to the path that was used to load the said library from within the library itself?

Note that I cannot have the agent that loaded the library in the first place hand me this parameter.

UPDATED: Here is way that works with static variables:

std::string wdir;

namespace {
    class dynamic_library_load_unload_handler {
         public:
              dynamic_library_load_unload_handler(){
                    Dl_info dl_info;
                    dladdr((void *) NP_Initialize, &dl_info);

                    std::string path(dl_info.dli_fname);
                    wdir = path.substr( 0, path.find_last_of( '/' ) +1 );
              }
              ~dynamic_library_load_unload_handler(){
                    // Code to execute when the library is unloaded
              }
    } dynamic_library_load_unload_handler_hook;
}

Solution

  • The dynamic linker actually searches several places to find each dynamic library. These include (from man ld.so):

    • Paths given by the environment variable LD_LIBRARY_PATH
    • Paths baked into the binary load the library under the DT_RUNPATH entry
    • The cache file /etc/ld.so.cache
    • /lib and /usr/lib

    If you want to get the path for a specific shared library, I would recommend the dladdr function. From the man page:

    The function dladdr() takes a function pointer and tries to resolve name and file where it is located. Information is stored in the Dl_info structure:

    typedef struct {
        const char *dli_fname;  /* Pathname of shared object that
                                   contains address */
        void       *dli_fbase;  /* Address at which shared object
                                   is loaded */
        const char *dli_sname;  /* Name of nearest symbol with address
                                   lower than addr */
        void       *dli_saddr;  /* Exact address of symbol named
                                   in dli_sname */
    } Dl_info;
    

    If no symbol matching addr could be found, then dli_sname and dli_saddr are set to NULL.

    dladdr() returns 0 on error, and non-zero on success.

    So you just give it a function pointer, and it will give you the name of the file which supplies it and a bunch of other information. So for instance, you could have a constructor in a library call this on itself to find out the full path of the library:

    #define _GNU_SOURCE
    #include <dlfcn.h>
    #include <stdio.h>
    
    __attribute__((constructor))
    void on_load(void) {
        Dl_info dl_info;
        dladdr((void *)on_load, &dl_info);
        fprintf(stderr, "module %s loaded\n", dl_info.dli_fname);
    }
    

    This function also works on OS X with the same semantics.