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

时间:2016-10-18 18:40:21

标签: c++

下面的代码演示了预期的(可以说是直观的)行为。就像在输入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-name\n";
        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;
}

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

$ 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()...
$ 

1 个答案:

答案 0 :(得分:4)

首先要做的事情:dlopen() 令人难以置信的平台特定,就像早期疾病症状和WebMD一样,您应该始终查阅平台的相关man页面。

即使dlopen()系列函数似乎符合IEEE Standard 1003.1, 2004 Edition,这也是正确的,尽管我无法告诉您今天的系统是如何符合此类标准的(例如Windows具有长期目标)历史shoddy POSIX compliance)。

在OS / X / BSD上,

  

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

强调我的。

在Linux上,

  

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

强调我的。

在Solaris上,

  

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

强调我的。