Search code examples
cshared-librariesdynamic-linkingdlopendynamic-loading

When do .so files get loaded Linux?


I have a shared object (a.so) which is linked to my executable myexe. a.so exposed a method called get_val(), which myexe is using.

Now when a.so will be loaded into myexe's process address space? is it when myexe calls get_val() API, or when myexe gets launched.


Solution

  • There are two (three) types of libraries:

    • static libraries (suffix: .a / .lib), which itself becomes part of the binary. Strictly speaking, it's not the whole library, it's those objects from the library which are required to satisfy unresolved links.
    • shared (dynamic) libraries (suffix: .so / .dll), which come in two flavors, distinguished by the time the library is loaded:
      • dynamic link library, which are libraries of which you told the compiler and linker and which you call like static libraries but which are not part of your library - they are loaded by the loader/linker (in Linux usually as part of __main() from libc by calling dlopen()).
      • dynamic load library for which you call dlopen() yourself.

    (The terms seem a bit fuzzy, I've seen different literature using different terms; the terms above is how I memorized it in order to remember the concepts.)

    So, if you use a.so without calling dlopen() yourself, a.so is a dynamic link library, so it is loaded at program start. In that case, removing a.so from the system will prevent your program from starting - it will be loaded, but it will fail before main() gets called.

    If you use a.so with calling dlopen() yourself, it's completely under your control.

    On your questions

    Q1: If you call dlopen() yourself, with RTLD_LAZY, the a.so will be loaded when the first unresolved call that can be resolved by a.so is made. If you call dlopen() yourself, with RTLD_NOW, a.so is loaded immediately, i.e. before dlopen() returns. If you do not call dlopen() yourself but let libc do the work for you, a.so will be loaded at program start.

    Q2: You delete a.so. If you call dlopen() with RTLD_LAZY, and do not run through the code that needs a.so, the program will run happily, otherwise a signal will be raised. If you do not call dlopen() but let libc do the work for you, the program will not start successfully.

    Q3: Effectively, there is no way to load a.so without calling dlopen() (or something equivalent that would replace it). The question is just, do you call dlopen() yourself, or do you let the environment (i.e. libc) do the work for you.

    Disclaimer: I'm not an expert for this stuff, and some parts of my answer may be wrong. I'll verify those parts of my answer on which I have doubts myself, i.e. whether it is libc that calls dlopen() or something else, and whether or not it's possible to have lazy binding even if you're not using dlopen() yourself. I'll update the answer once I have the results.