shared-librarieselfdlopendynamic-loadingdlclose

Is there a way I can add a shared object file (.so) to ld.so.cache?


I wrote a simple C program that does a dlopen on an shared object:

 handle = dlopen ("./MySharedObject.so", RTLD_LAZY);
        if (!handle) {
            fputs (dlerror(), stderr);
            exit(1);
        }
sleep(20)
dlclose(..)

Now I compile my program as an executable and run multiple instances of the executable simultaneously on the same machine. I thought the handle that will be returned in all the runs will be same. But, it seems that the loaded shared objects in the ld.so.cache are the only ones that can return the same handle.

My goal is not to load the same code twice using the dlopen. Does anyone have any idea on how this can be achieved?


Solution

  • I thought the handle that will be returned in all the runs will be same.

    It wouldn't be, but that doesn't mean what you appear to think it means.

    Even though the handle is different, the shared library still works and is still shared between the multiple processes. In other words, there is no problem for you to fix here.

    But, it seems that the loaded shared objects in the ld.so.cache are the only ones that can return the same handle.

    This is also false: there is absolutely no guarantee that objects listed in ld.so.cache will use the same handle in different processes.

    Update:

    I assumed that the handle is pointer to the loaded contents of the shared library.

    That is incorrect: under GLIBC, the handle is a pointer to a heap-allocated block describing a particular library. It does not point into the library itself.

    If I dlsym a symbol, it ideally should return the start of where the symbols definition is loaded.

    Correct.

    In this case I get different dlsym values. Does this means that the symbol is loaded twice?

    No, it does not. Through the magic of virtual memory, the same physical pages of RAM can appear at different addresses in different processes. This is exceedingly common for shared libraries when ASLR is on.

    For example, here are two executions of the same /bin/date binary:

    $ ldd /bin/date | grep libc.so.6
            libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f60ff32f000)
    $ ldd /bin/date | grep libc.so.6
            libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007ffa38e2a000)
    

    Note that libc.so.6 got loaded at different addresses (while still being shared with all the other currently running processes on the system).

    It is also very easy to create a situation where the same physical RAM pages appear at different addresses within a single process: just call mmap(fd, ..., 0) on the same file descriptor twice.