9

这里的答案表明 __attribute__((constructor)) 不是在静态初始化之后调用的,而是按声明顺序调用的。

那么,如果不保证在所有数据初始化时调用它,它的目的是什么?我们也可以在 Foo 构造函数中包含我们的 ((constructor)) 代码。

我正在寻找的是一种在共享库中拥有在初始化所有静态数据并调用静态构造函数后将执行的代码的方法。我看到人们推荐 __attribute__((constructor)) 作为 DllMain 的替代品;我们可以看到这是错误的,因为一些静态数据可能还没有初始化。

当然,在单个文件(编译单元)中,我们可以安排静态。但是在一个典型的程序中有很多文件。有没有办法保证一个文件中的 ((constructor)) 在共享库中的所有其他静态变量都被初始化后肯定会被调用?

如果我将带有静态初始化(构造函数、对象等)的文件放在 gcc 命令行的末尾:

g++ -shared -fPIC source1.o source2.o MyLastInitChance.o

这个文件的静态构造函数是否保证最后被调用?我进行了实验,当我更改源文件的顺序时,printfs 的顺序发生了变化;但它是否在某处指定并保证在编译系统/计算机中相同?

例如,引用:

在链接时,gcc 驱动程序将 crtbegin.o 放在所有可重定位文件之前,并将 crtend.o 放在所有可重定位文件之后。©

据我了解,上面的引用暗示传递给链接器的 .o 文件的顺序定义了静态初始化的顺序。我对么?

另一个有趣的可能解决方案可能是编写一个 GCC 插件来调整静态初始化(例如,将代码添加到 .ctors 部分等)。但这只是一个想法,也许有人可以扩展。

这里介绍了另一种可能的解决方案。简而言之,可以使用外部构建后工具对可执行文件(库)中的 .ctors 条目进行重新排序。但我不是 ELF 格式的专家;我想知道以这种方式调整 .so 文件是否可行且足够容易。

我感兴趣的是解决一个特定的问题,或者证明它是不可能解决的(至少为什么上面的解决方案不起作用)。

4

4 回答 4

13

您可以尝试将链接器脚本用于ld. 你可以在这里阅读更多关于它的信息,但我猜你正在寻找的是

.ctors : { *(SORT(.ctors)) MyLastInitChance.o(SORT(.ctors)) }
.dtors : { *(SORT(.dtors)) MyLastInitChance.o(SORT(.dtors)) }

SECTIONS{...}块中。这应该重新排列.ctors部分,以便提供的文件将其构造函数称为最后一个。显然,如果您发现自己需要更高级的解决方案;)

提示:编写自己的链接脚本很乏味。使用ld'--verbose选项打印出使用的链接脚本并修改它。-T然后使用switch添加链接脚本。

于 2012-06-25T23:40:23.267 回答
2

属性((constructor))__的最大优势是与每个块相关联的优先级,并且特别有助于您的案例。

您有两个具有数据风险的代码块(应首先执行一组)。这是单个静态块无法实现的。由于顺序混乱,使用一个静态块和一个属性((constructor))__ 不会解决您的问题。

处理该问题的最佳方法是让两个属性((constructor))__ 具有两个不同的优先级。将现有的静态初始化块移至较高优先级 (0),将另一个代码块移至较低优先级。

于 2012-06-22T17:51:14.813 回答
2

请参阅: http: //gcc.gnu.org/ml/gcc-help/2011-05/msg00220.html和答案http://gcc.gnu.org/ml/gcc-help/2011-05/msg00221 .html

特别是从答案中引用:

所有具有 init_priority 属性的对象都在任何没有 init_priority 属性的对象之前构造。

请注意,它实际上是关于__attribute__((init_priority))而不是关于,__attribute__((constructor))但我相信它们实际上都在 gcc 中使用相同的代码,分别在 gnu 链接器中。首先只是对应C++对象,即调用它们的构造函数/析构函数,后者是关于将特定函数标记为构造函数或析构函数。

恕我直言,__attribute__((constructor))存在主要是因为 C,而不是 C++。

于 2012-06-22T19:23:53.473 回答
2

你能为这个全局实现“首次使用时构造”模式吗?

例如

Magic& gMagic()
{
    static Magic magic;
    return magic;
}

它将在所有常规静态 ctor 之后构建,但在任何常规代码需要它之前。

于 2012-06-26T19:48:10.717 回答