__attribute __((构造函数))调用顺序混淆

这里的答案表明__attribute __((构造函数)) 静态初始化之后不被调用,它在声明顺序中被调用。

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

我正在寻找的是在共享库中有一个代码,在所有静态数据初始化并调用静态构造函数之后执行。 我看到有人推荐__attribute __((构造函数))来代替DllMain; 因为我们可以看到这是错误的,因为一些静态数据可能还没有被初始化。

当然,在单个文件(编译单元)中,我们可以安排静态。 但在典型的程序中有很多文件。 有一种方法可以保证((构造函数))在一个共享库中的所有其他静态都被初始化之后肯定会被调用吗?

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

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

这个文件的静态构造函数保证被称为最后? 我尝试过,当我改变源文件的顺序时,printfs的顺序被改变了; 但它是指定的地方,并保证在编译系统/计算机是相同的?

例如,一个报价:

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

从我理解上面的引用意味着传递给链接器的.o文件的顺序定义了静态初始化的顺序。 我对么?

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

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

我感兴趣的是解决一个特定的问题,或者certificate不可能解决(至less为什么上面的解决scheme不起作用)。

Solutions Collecting From Web of "__attribute __((构造函数))调用顺序混淆"

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

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

SECTIONS{...}块中。 这应该重新排列。所以提供文件将调用它的构造函数作为最后一个。 显然,如果你觉得自己需要一个解决方案,也可以使用更先进的解决方案;)

提示:编写你自己的链接脚本是乏味的。 使用ld--verbose选项打印出使用过的链接脚本并进行修改。 然后使用-T开关添加您的链接脚本。

属性 ((构造函数))__的最大优点是与每个块关联的优先级,并专门帮助您的情况。

你有两块有数据危险的代码块(一组应该先执行)。 这是单个静态块无法实现的。 使用一个静态块和一个属性 ((构造函数))__将无法解决您的问题,因为有关顺序混淆。

处理这个问题的最好方法是拥有两个不同的优先级的属性 ((构造函数))。 将现有的静态初始化块移到较高的优先级(0),将另一个代码块移到较低的优先级。

看到这个: 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 ++。

你能否为这个全球实施一个“首先使用的构造”模式?

例如

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

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