全局构造函数调用不在.int_array节中
Global constructor call not in .init_array section
我正试图在嵌入式目标(ARM Cortex-M3)上添加全局构造函数支持。假设我有以下代码:
class foobar
{
int i;
public:
foobar()
{
i = 100;
}
void inc()
{
i++;
}
};
foobar foo;
int main()
{
foo.inc();
for (;;);
}
我这样编译它:
arm-none-eabi-g++ -O0 -gdwarf-2 -mcpu=cortex-m3 -mthumb -c foo.cpp -o foo.o
当我查看带有objdump的.init_array部分时,它显示.init_section的大小为零。
我确实得到了一个名为_Z41__static_initialization_and_destruction_0ii
的符号。当我反汇编对象文件时,我看到全局构造是在static_initization_and_disation符号中完成的。
为什么在.init_section中没有添加指向该符号的指针?
我知道这个问题已经问了将近两年了,但我只需要自己用GCC弄清楚裸金属C++初始化的机制,所以我想在这里分享细节。事实证明,网络上有很多过时或令人困惑的信息。例如,经常提到的collect2
包装器似乎不用于ARM ELF目标,因为它的任意部分支持可以实现下面描述的方法。
首先,当我使用Sourcery CodeBench Lite 2012.09-63使用给定的命令行编译上面的代码时,我确实看到了正确的.init_array
节大小4:
$ arm-none-eabi-objdump -h foo.o
foo.o: file format elf32-littlearm
Sections:
Idx Name Size VMA LMA File off Algn
...
13 .init_array 00000004 00000000 00000000 0000010c 2**2
CONTENTS, ALLOC, LOAD, RELOC, DATA
...
当我查看部分内容时,它只包含0:
$ arm-none-eabi-objdump -j .init_array -s foo.o
Contents of section .init_array:
0000 00000000 ....
然而,也有一个重新定位部分将其正确设置为_GLOBAL__sub_I_foo
:
$ arm-none-eabi-objdump -x foo.o
...
RELOCATION RECORDS FOR [.init_array]:
OFFSET TYPE VALUE
00000000 R_ARM_TARGET1 _GLOBAL__sub_I_foo
通常,.init_array
指向所有_GLOBAL__sub_I_XXX
初始值设定项存根,每个存根都调用自己的_Z41__static_initialization_and_destruction_0ii
副本(是的,它是多重定义的),后者使用适当的参数调用构造函数。
因为我在构建中使用-nostdlib
,所以我不能使用CodeSourcery的__libc_init_array
来执行.init_array
,所以我需要自己调用静态初始化程序:
extern "C"
{
extern void (**__init_array_start)();
extern void (**__init_array_end)();
inline void static_init()
{
for (void (**p)() = __init_array_start; p < __init_array_end; ++p)
(*p)();
}
}
__init_array_start
和__init_array_end
由链接器脚本定义:
. = ALIGN(4);
.init_array :
{
__init_array_start = .;
KEEP (*(.init_array*))
__init_array_end = .;
}
这种方法似乎既适用于CodeSourcery交叉编译器,也适用于本机ARM GCC,例如在Ubuntu 12.10 for ARM中。支持这两个编译器是使用-nostdlib
而不依赖CodeSourcery CS3裸机支持的原因之一。
Timmmm,
我刚刚在nRF51822上遇到了同样的问题,并通过在股票Nordic.ld文件的几行周围添加KEEP()来解决:
KEEP(*(SORT(.init_array.*)))
KEEP(*(.init_array))
同时,我对fini_array区域也做了同样的操作。解决了我的问题,链接器仍然可以删除其他未使用的部分。。。
由于gcc的-c参数,您只生成了一个对象文件。要创建.init部分,我认为您需要将.o链接到一个实际的可执行文件或共享库中。尝试删除-c参数并将输出文件重命名为"foo",然后使用反汇编程序检查生成的可执行文件。
如果仔细观察,_Z41__static_initialization_and_destruction_0ii
将在全局构造函数中调用。哪个inturn将在.init_array
部分(在CodeSourcery的arm-none-eabi-
中)或其他函数(如果使用Linux g++,则为__main()
)中链接。()这应该在启动时或main()
时调用。另请参阅此链接。
我遇到了一个类似的问题,我的构造函数没有被调用(nRF51822 Cortex-M0 with GCC)。问题原来是由这个链接器标志引起的:
-Wl,--gc-sections
别问我为什么!我以为它只是删除了死代码。
- 如何从map<pair<string,int>,pair<string,Array>>中迭代和查找?
- 如何将 int[4] 转换为 std::array<int,4>?
- 是否有可能在没有复制的情况下传递 std::vector<int> 作为参数来获得 std::vector<std::array<int, 3>>?
- 尝试使用 Array 类的模板构造整数数组时,错误:为什么数组类型"int [5]"不可分配,
- 如何就地构造 std::map<int, std::array<Class, 2>>?
- 如何从方法返回静态常量 int std::array?
- 尝试使用 const int std::array 时出错
- Visual Studio 不采用 array: int magicSquare[n][n]?
- 混淆从"array of int[]"到"pointer to int"的显式衰减?
- 为什么我们不能将 int array[] 传递给 hoo(int* &p)?
- "Converting" 从 int[] 到 std::array at fread?
- Int Array[]打印不好
- 从 int 转换为 std::array<unsigned char, 1ul>::value_type 可能会改变其值
- 为什么 new int[n] 有效,而 int array[n] 无效
- 带有参数的 func return list (int arry[int]<int>, int array[int])
- iPhone SDK 2d int array
- 为什么是 int array[][20]
- int * array[60] 和 int * array = new int(60);之间的区别
- Int *array = new Int [n];这个函数到底在做什么
- 错误 LNK2001:未解析的外部符号"int * array"