这有很多可能的原因。您访问尚未创建的对象的范围(因为未定义跨不同翻译单元创建对象的顺序)我认为在这种情况下很可能,并且范围为您的构建环境中的错误。
要使自己的函数在其他构造函数之前被调用,您需要在此处constructor (priority)
描述一个属性。GCC 为每个文件的构造函数输入部分保留优先级。它按照这些优先级的顺序将它们联系起来。在我的 linux 系统的链接器脚本中,该代码如下所示(使用 输出):ld -verbose
.ctors :
{
/* gcc uses crtbegin.o to find the start of
the constructors, so we make sure it is
first. Because this is a wildcard, it
doesn't matter if the user does not
actually link against crtbegin.o; the
linker won't look for a file to match a
wildcard. The wildcard also means that it
doesn't matter which directory crtbegin.o
is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*crtbegin?.o(.ctors))
/* We don't want to include the .ctor section from
the crtend.o file until after the sorted ctors.
The .ctor section from the crtend file contains the
end of ctors marker and it must be last */
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
}
您可能希望给它一个低优先级以使其在具有更高优先级编号的其他已注册 ctor 函数之前执行。但是从外观上看,似乎没有编号的构造函数将首先执行。完全不确定。最好你试一试。如果你想在 _do_global_ctors_aux 之前调用你的函数,你必须释放_init
当你的程序被 ELF 加载器加载时通常执行的原始函数(查看-init
ld 的选项)。我已经有一段时间没有搞砸它了,但我记得它必须做一些初始化的私密细节,所以我不会尝试替换它。尝试使用我链接到的构造函数属性。但是,要非常小心。您的代码可能会在cout
构造其他重要对象之前执行。
更新:我做了一个测试,它实际上是反向执行 ctor 函数。因此,首先链接的 ctor 函数稍后执行。这段代码恰好在 gcc 源代码的 crtstuff.c 中:
func_ptr *p;
for (p = __CTOR_END__ - 1; *p != (func_ptr) -1; p--)
(*p) ();
我做了一个小测试:
void dothat() { }
struct f {
f() { dothat(); }
} f_;
void doit() __attribute__((constructor (0)));
void doit() { }
int main() { }
与--print-map
产量等相关的输出是:
.ctors 0x080494f4 0x10
*crtbegin.o(.ctors)
.ctors 0x080494f4 0x4 /usr/lib/gcc/i686-pc-linux-gnu/4.3.2/crtbegin.o
*crtbegin?.o(.ctors)
*(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors)
.ctors 0x080494f8 0x4 /tmp/ccyzWBjs.o
*(SORT(.ctors.*))
.ctors.65535 0x080494fc 0x4 /tmp/ccyzWBjs.o
*(.ctors)
.ctors 0x08049500 0x4 /usr/lib/gcc/i686-pc-linux-gnu/4.3.2/crtend.o
注意.ctors.65535
我们的属性 priority 是如何隐式创建的部分0
。现在,如果您给予它优先级,gcc 会发出警告,这是完全正确的:p
test.cpp:7:警告:从 0 到 100 的构造函数优先级保留用于实现
我通过中断doit
and对其进行了测试dothat
,它以我们期望的顺序调用它们。玩得开心!