我在Linux(Ubuntu 12.04,gcc 4.6.3)上,尝试使dlopen/接近我的意愿,以便制作一个基于插件的应用程序,该应用程序可以在需要时(例如,如果重新编译)重新加载其插件。 。

基本原理很简单:dlopen插件;使用它,跟踪其所有正在使用的符号。当需要重新加载时,请清理所有符号并dlclose插件。

我整理了一个简单的演示应用程序“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'错误。如果是后者,是否有更可靠的方法来确定是否仍在加载库?

最佳答案

在以下程序中,我的观察与您不同:

// 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

顺便说一下,正如我的manydl.c示例所展示的,您实际上可以避免任何dlclose -ing。在实践中,不打扰dlclose -ing意味着仅很小的地址空间泄漏,而在实践中并不重要。 (您可以dlopen将近一百万个不同的共享对象,而不会受到太大的伤害)。

要知道何时卸载共享对象,请使用dlclose -d插件的“析构函数”功能(例如,C++中的静态数据的析构函数,或C代码中的attribute((destructor))),因为它们是从卸载dlclose内部调用的。

关于c++ - 如何知道dlclose()ed库是否真的完成了进程?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/11041669/

10-09 06:42