2012-06-14 109 views
2

我在Linux上(Ubuntu 12.04,gcc 4.6.3),試圖彎曲dlopen /接近我的意志,以便製作一個基於插件的應用程序,可以在必要時重新加載插件(例如,如果它們是重新編譯)。如何知道過程是否真正完成了dlclose()庫?

基本理論很簡單:dlopen插件;使用它,跟蹤所有正在使用的符號。當需要重新加載時,清理所有符號並關閉插件。

我一起扔一個簡單的演示應用程序,「TEST.CPP」:

#include <dlfcn.h> 
#include <iostream> 
using namespace std; 
int main(int argc, char** argv) 
{ 
    if (argc > 1) 
    { 
     void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL); 
     if (!h) 
     { 
      cerr << "ERROR: " << dlerror() << endl; 
      return 1; 
     } 
     cin.get(); 
     if (dlclose(h)) 
     { 
      cerr << "ERROR: " << dlerror() << endl; 
      return 2; 
     } 
     cin.get(); 
    } 
    return 0; 
} 

編譯:

g++ test.cpp -o test -ldl 

爲了可以作爲參數傳遞到上面的一個簡單的圖書館代碼,使用:

touch libtest.cpp && g++ -rdynamic -shared libtest.cpp -o libtest.so 

然後運行

./test ./libtest.so 

這是問題;如果在按[Enter]一次後(即加載並假定卸載庫之後),則運行'pmap'以檢查在'test'中加載了哪些庫,它會告訴你libtest.so仍然存在!現在這是儘管從dlclose()有效返回,並沒有合理的方式,引用計數可以在此之前微升到1以上(這可以通過嘗試第二個dlclose()來驗證 - 它會給出錯誤返回,說它已經是關閉)。

因此,無論是Linux 從來沒有卸載dlopen()ed庫(違反文檔),或'pmap'是錯誤的。如果是後者,是否有更可靠的方法來確定庫是否仍然被加載?

回答

2

我不與以下程序觀察和你一樣:

// file soq.c 
#include <dlfcn.h> 
#include <iostream> 
#include <cstdio> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
using namespace std; 
int main(int argc, char** argv) 
{ 
    char cmd[60]; 
    snprintf(cmd, sizeof(cmd), "pmap %d", getpid()); 
    if (argc > 1) 
    { 
     void* h = dlopen(argv[1], RTLD_NOW|RTLD_LOCAL); 
     if (!h) 
     { 
      cerr << "ERROR: " << dlerror() << endl; 
      return 1; 
     } 
    cerr << "after dlopen " << argv[1] << endl; 
    system(cmd); 
     cin.get(); 
     if (dlclose(h)) 
     { 
      cerr << "ERROR: " << dlerror() << endl; 
      return 2; 
     } 
     cin.get(); 
    cerr << "after close " << argv[1] << endl; 
    system(cmd); 
    } 
    return 0; 
} 

我正在如預期:

% ./soq ./libempty.so 
./soq ./libempty.so 
after dlopen ./libempty.so 
5276: ./soq ./libempty.so 
0000000000400000  8K r-x-- /home/basile/tmp/soq 
0000000000601000  4K rw--- /home/basile/tmp/soq 
0000000001b4d000 132K rw--- [ anon ] 
00007f1dbfd01000  4K r-x-- /home/basile/tmp/libempty.so 
00007f1dbfd02000 2044K ----- /home/basile/tmp/libempty.so 
00007f1dbff01000  4K rw--- /home/basile/tmp/libempty.so 
00007f1dbff02000 1524K r-x-- /lib/x86_64-linux-gnu/libc-2.13.so 
00007f1dc007f000 2048K ----- /lib/x86_64-linux-gnu/libc-2.13.so 
00007f1dc027f000  16K r---- /lib/x86_64-linux-gnu/libc-2.13.so 
00007f1dc0283000  4K rw--- /lib/x86_64-linux-gnu/libc-2.13.so 
00007f1dc0284000  20K rw--- [ anon ] 
00007f1dc0289000  84K r-x-- /lib/x86_64-linux-gnu/libgcc_s.so.1 
00007f1dc029e000 2048K ----- /lib/x86_64-linux-gnu/libgcc_s.so.1 
00007f1dc049e000  4K rw--- /lib/x86_64-linux-gnu/libgcc_s.so.1 
00007f1dc049f000 516K r-x-- /lib/x86_64-linux-gnu/libm-2.13.so 
00007f1dc0520000 2044K ----- /lib/x86_64-linux-gnu/libm-2.13.so 
00007f1dc071f000  4K r---- /lib/x86_64-linux-gnu/libm-2.13.so 
00007f1dc0720000  4K rw--- /lib/x86_64-linux-gnu/libm-2.13.so 
00007f1dc0721000 928K r-x-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 
00007f1dc0809000 2048K ----- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 
00007f1dc0a09000  32K r---- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 
00007f1dc0a11000  8K rw--- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 
00007f1dc0a13000  84K rw--- [ anon ] 
00007f1dc0a28000  8K r-x-- /lib/x86_64-linux-gnu/libdl-2.13.so 
00007f1dc0a2a000 2048K ----- /lib/x86_64-linux-gnu/libdl-2.13.so 
00007f1dc0c2a000  4K r---- /lib/x86_64-linux-gnu/libdl-2.13.so 
00007f1dc0c2b000  4K rw--- /lib/x86_64-linux-gnu/libdl-2.13.so 
00007f1dc0c2c000 128K r-x-- /lib/x86_64-linux-gnu/ld-2.13.so 
00007f1dc0e1c000  20K rw--- [ anon ] 
00007f1dc0e49000  8K rw--- [ anon ] 
00007f1dc0e4b000  4K r---- /lib/x86_64-linux-gnu/ld-2.13.so 
00007f1dc0e4c000  4K rw--- /lib/x86_64-linux-gnu/ld-2.13.so 
00007f1dc0e4d000  4K rw--- [ anon ] 
00007fff076c3000 132K rw--- [ stack ] 
00007fff077b4000  4K r-x-- [ anon ] 
ffffffffff600000  4K r-x-- [ anon ] 
total   15984K 




after close ./libempty.so 
5276: ./soq ./libempty.so 
0000000000400000  8K r-x-- /home/basile/tmp/soq 
0000000000601000  4K rw--- /home/basile/tmp/soq 
0000000001b4d000 132K rw--- [ anon ] 
00007f1dbff02000 1524K r-x-- /lib/x86_64-linux-gnu/libc-2.13.so 
00007f1dc007f000 2048K ----- /lib/x86_64-linux-gnu/libc-2.13.so 
00007f1dc027f000  16K r---- /lib/x86_64-linux-gnu/libc-2.13.so 
00007f1dc0283000  4K rw--- /lib/x86_64-linux-gnu/libc-2.13.so 
00007f1dc0284000  20K rw--- [ anon ] 
00007f1dc0289000  84K r-x-- /lib/x86_64-linux-gnu/libgcc_s.so.1 
00007f1dc029e000 2048K ----- /lib/x86_64-linux-gnu/libgcc_s.so.1 
00007f1dc049e000  4K rw--- /lib/x86_64-linux-gnu/libgcc_s.so.1 
00007f1dc049f000 516K r-x-- /lib/x86_64-linux-gnu/libm-2.13.so 
00007f1dc0520000 2044K ----- /lib/x86_64-linux-gnu/libm-2.13.so 
00007f1dc071f000  4K r---- /lib/x86_64-linux-gnu/libm-2.13.so 
00007f1dc0720000  4K rw--- /lib/x86_64-linux-gnu/libm-2.13.so 
00007f1dc0721000 928K r-x-- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 
00007f1dc0809000 2048K ----- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 
00007f1dc0a09000  32K r---- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 
00007f1dc0a11000  8K rw--- /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.17 
00007f1dc0a13000  84K rw--- [ anon ] 
00007f1dc0a28000  8K r-x-- /lib/x86_64-linux-gnu/libdl-2.13.so 
00007f1dc0a2a000 2048K ----- /lib/x86_64-linux-gnu/libdl-2.13.so 
00007f1dc0c2a000  4K r---- /lib/x86_64-linux-gnu/libdl-2.13.so 
00007f1dc0c2b000  4K rw--- /lib/x86_64-linux-gnu/libdl-2.13.so 
00007f1dc0c2c000 128K r-x-- /lib/x86_64-linux-gnu/ld-2.13.so 
00007f1dc0e1c000  20K rw--- [ anon ] 
00007f1dc0e48000  12K rw--- [ anon ] 
00007f1dc0e4b000  4K r---- /lib/x86_64-linux-gnu/ld-2.13.so 
00007f1dc0e4c000  4K rw--- /lib/x86_64-linux-gnu/ld-2.13.so 
00007f1dc0e4d000  4K rw--- [ anon ] 
00007fff076c3000 132K rw--- [ stack ] 
00007fff077b4000  4K r-x-- [ anon ] 
ffffffffff600000  4K r-x-- [ anon ] 
total   13936K 

所以你沒有運行pmap錯誤。

順便說一句,您可以避免任何dlclose -ing在實踐中,因爲我的manydl.c示例演示。在實踐中,不打擾dlclose-意味着只有一個微小的地址空間泄漏,在實踐中沒有什麼大不了的。 (你可以dlopen將近一百萬個不同的共享對象沒有太大的傷害)。

而當一個共享對象被卸載知道,用你的dlclose -d插件的「析構」的功能(例如,在C++靜態數據,或在例如attribute((destructor))的析構函數Ç代碼),因爲它們是從稱爲裏面卸dlclose

相關問題