This is the mail archive of the libc-help@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Dynamic library loading inner workings


Hello,

I'm working on a program which uses the nice features of dlopen/dlclose. However I've realized that the approach has a
significant drawback, and I do not quite understand why it works as it does. So here my problem description:
I have three libraries, let's call them libA, libB, and libC, and imagine that libA links against libC and libB links also
against libC, i.e.
libA --> libC
libB --> libC
libA and libB are otherwise not related. To make it more real life, we use now:
libQtGui.so --> libQtCore.so
libQtXml.so --> libQtCore.so

Neither libQtGui.so links against libQtXml.so nor libQtXml.so against libQtGui.so. Attached is a program, which dlopen's two
libraries (arguments on the commandline) and dlclose's the first one. Additionally it prints the loaded libraries right before
dlclosing the first library, right after dlclosing the first one and after dlclosing the second one.

Compile the program with: g++ -ldl -o test_dlopen test_dlopen.cpp
Now to the problem:
 - The program is started with (adapt the path to your system): ./test_dlopen /usr/lib/qt4/libQt{Gui,Xml}.so 
   - libQtGui.so is still in memory after dlclose
   - dlopen libQtGui.so once again would not reopen from harddisk, but rather give the handle to the library in memory
 - The program is started with: ./test_dlopen /usr/lib/qt4/libQt{Xml,Gui}.so
   - In this scenario libQtXml.so is not resident in memory after dlclose.
   - dlopenlibQtXml.so once again would open from harddisk, i.e. it would recognize changes if it would have been recompiled.
 - The program is started with: LD_PRELOAD=/usr/lib/qt4/libQtCore.so ./test_dlopen /usr/lib/qt4/libQt{Gui,Xml}.so
   - This time libQtGui.so is unloaded correctly and not resident in memory anymore.
   - Reloading it would recognize changes made in the library.

In all three scenarios after closing the 2nd library everything is unloaded from memory, so it's not a problem of not being able
to unload at all.

So basically my question is:
Why does the first case fail? Fail in this case means, that libQtGui.so is still in memory and cannot be reloaded from harddisk.

Yes I know, that the libraries don't need to be unloaded from memory (as defined in the standard), but on linux they are unloaded,
and if they are not unload from memory there is no way to reopen from harddisk!

Regards
Andreas
// g++ -ldl -o test_dlopen test_dlopen.cpp && ./test_dlopen /usr/lib/qt4/libQtGui.so /usr/lib/qt4/libQtXml.so

#include <dlfcn.h>
#include <iostream>
#include <cstdio>
#include <link.h>

int cb(struct dl_phdr_info* info, size_t size, void* data)
{
  std::cout << info->dlpi_name << std::endl;
  return 0;
}

typedef void (*test_fct)();

int main(int argc, char** argv)
{
  if ( argc != 3 ) {
    std::cout << "Usage: " << argv[0] << " path_to_libQt{Gui,Xml}.so path_to_libQt{Xml,Gui}.so" << std::endl;
    return 1;
  }
  const char* p1 = argv[1];
  const char* p2 = argv[2];
  void* h1 = dlopen(p1, RTLD_NOW|RTLD_LOCAL);
  void* h2 = dlopen(p2, RTLD_NOW|RTLD_LOCAL);

  std::cout << "Loaded libraries, after " << argv[1] << " and " << argv[2] << " have been loaded" << std::endl;
  dl_iterate_phdr(cb, 0);
  std::cout << "dlclose return: " << dlclose(h1) << std::endl;  // should return 0
  std::cout << "Loaded libraries after " << argv[1] << " has been closed..." << std::endl;
  dl_iterate_phdr(cb, 0);

  std::cout << "dlclose return h1: " << dlclose(h1) << std::endl;  // should return -1
  std::cout << "dlclose return h2: " << dlclose(h2) << std::endl;  // should return 0
  
  std::cout << "Loaded libraries after all libraries have been closed..." << std::endl;
  dl_iterate_phdr(cb, 0);

  return 0;
}

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]