Linux共享库init& deinit时也使用c ++静态初始化程序

时间:2013-10-24 21:23:12

标签: c++ linux gcc initialization shared-libraries

我希望自动调用初始化和取消初始化我的共享库。

在我的共享库中,我需要对C ++对象进行一些静态初始化,其中包括使用第三方代码(例如UnitTest ++)。 当执行我的init函数时,我需要保证,C ++对象(所有链接的翻译单元)的所有静态初始化都已完成(反之亦然);因此,与main()的执行在C ++程序中所期望的条件相同。

我已经看到很多关于linux共享库init / deinit的信息,例如像:

但提供的解决方案不符合我的需求。在两种方法(__attribute__((constructor))和偶数-Wl,-init,<function name>)中,似乎在完全完成C ++对象的静态初始化之前调用了init函数。

我还和__attribute__ ((init_priority(…)))一起玩过:

class InitAndDeinit {
public:
    InitAndDeinit() {
        // Do some initialization
    }
    ~InitAndDeinit() {
        // Do some cleanup
    }
} initAndDeinit __attribute__((init_priority(65535)));

但是,这也不会将呼叫置于所需的位置;即使是__attribute__((constructor(65535)))

我用gcc 4.6.4,4.7.3和4.8.1进行了测试(4.6.4显示了对__attribute__((constructor))的排序略有不同的行为。

有什么建议吗?

我目前的解决方法是提供必须由应用程序手动调用的导出函数(lib_init()和lib_deinit())。

2 个答案:

答案 0 :(得分:1)

这是一种可能的解决方案。

TU中的静态对象按其定义顺序初始化。将特殊类型T的静态对象的定义附加到每个源文件的末尾。 T的构造函数应该增加静态零初始化成员。一旦计数器达到模块中的源文件数(由构建脚本确定),请调用lib_init()

在计数器减少回零后调用

lib_deinit()

每个库都应该有自己的T

您应该能够修改您的makefile,这样您就不必在物理上改变源文件。例如,而不是g++ -c foo.C使用g++ -c myspecialstaticinitcode.C -o foo.C -include foo.C或类似的东西。

答案 1 :(得分:0)

@Joe静态对象的初始化和初始化的顺序由处理.ctors和.dtors节或.init_array和fini_array节的加载程序或链接程序确定。当加载程序在返回之前调用dlopen()时,将进行全局构造函数和静态对象初始化。除非使用的共享库是通过-nostartfiles或-nostdlib编译的,否则它可能已经发生了。运行时ABI规范没有提到它是如何实现的,它取决于链接器/加载器。但是,该标准指出,必须先进行静态数据和全局构造函数初始化,然后才能调用共享库的任何功能。

请参见下文。

5.2。库构造函数和析构函数 库应使用gcc attribute ((constructor))和 attribute ((destructor))函数属性导出初始化和清理例程。有关这些信息,请参见gcc信息页面。构造函数例程在dlopen返回之前执行(如果在加载时加载了库,则在main()启动之前)将被执行。析构函数例程在dlclose返回之前执行(如果在加载时加载了库,则在exit()或main()完成之后)执行。这些功能的C原型是: void 属性((构造函数))my_init(void); void 属性((析构函数))my_fini(void);

不得使用gcc参数-nostartfiles'' or-nostdlib编译共享库。”如果使用这些参数,则将不执行构造函数/析构函数例程(除非采取特殊措施)。