是动态加载库中的静态c++对象,在dlopen()返回之前初始化

Are static c++ objects in dynamically loaded libraries initialized before dlopen() returns?

本文关键字:dlopen 返回 初始化 对象 加载 动态 c++ 静态      更新时间:2023-10-16

下面的代码演示了预期的(而且可以说是直观的)行为。就像可执行程序中的静态对象在main()进入之前被初始化一样,动态加载库中的静态对象应该在dlopen()返回之前被初始化。

问题是:在运行时加载的库的这种行为是否以任何方式得到保证,或者它只是一个方便的事故或幸运的实现细节?我们是否可以依赖正在调用的库中静态对象的构造函数,或者我们是否必须求助于替代方案,例如标记为__attribute__((constructor))的函数,以确保在dlopen()调用范围内的一些期望行为?

// libtest.cpp
#include <iostream>
namespace
{
    class Test
    {
    public:
        Test()  { std::cerr << "In Test()...n"; }
        ~Test() { std::cerr << "In ~Test()...n"; }
    };
    Test    test; // when is this initialized?
}
// testso.cpp
#include <dlfcn.h>
#include <iostream>
int main( int ac, char* av[] )
{
    if ( ac < 2 )
    {
        std::cerr << "Usage: " << av[0] << "library-namen";
        return 1;
    }
    std::cerr << "Before dlopen()...n";
    ::dlerror();
    void*    _handle(::dlopen( av[1], RTLD_NOW ));
    std::cerr << "After dlopen()...n";
    if ( !_handle )
    {
        std::cerr << "Error: " << ::dlerror() << ", exiting...n";
        return 2;
    }
    ::dlclose( _handle );
    std::cerr << "After dlclose()...n";
    return 0;
}

编译并运行(注意dlopen()返回前Test()调用):

$ g++ -o libtest.so -shared -fPIC libtest.cpp
$ g++ -o testso -ldl testso.cpp
$ ./testso ./libtest.so
Before dlopen()...
In Test()...
After dlopen()...
In ~Test()...
After dlclose()...
$ 

首先:dlopen()令人难以置信的平台特定的,对于早期疾病症状和WebMD的情况,您应该始终咨询您的平台相关的man页面。

这是正确的,即使dlopen()函数家族似乎符合IEEE标准1003.1,2004版,尽管我不能告诉你今天的系统与这些标准的兼容性有多高(例如Windows有一个长期的劣质POSIX兼容性历史)。


OS/X/BSD上yes:

dlopen()检查path指定的mach-o文件。如果文件与当前进程兼容并且尚未加载到当前进程,它被加载并链接。链接后,如果它包含任何初始化函数,则在dlopen()之前调用它们回报。

<>共舞,强调我的。


在Linux上,yes:

共享对象可以使用__attribute__((constructor))__attribute__((destructor))功能属性。构造函数在dlopen()之前执行在dlclose()之前执行析构函数回报。

<>共舞,强调我的。


在Solaris上,yes:

作为加载新对象的一部分,在dlopen()返回之前调用对象内的初始化代码。这个初始化是用户代码,因此,可能会产生dlopen()无法捕获的错误。

<>共舞,强调我的。