6

我想要自动调用来初始化和取消初始化我的共享库。

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

我已经看到了很多关于 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())。

4

2 回答 2

1

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

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

lib_deinit()在计数器减回零后调用。

每个库都应该有自己的T.

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

于 2013-10-24T22:36:28.837 回答
0

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

请看下文。

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

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

于 2020-03-05T09:44:50.223 回答