Ing*_*onk 9 c++ gcc constructor
我正在尝试在嵌入式目标(ARM Cortex-M3)上添加全局构造函数支持.让我说我有以下代码:
class foobar
{
int i;
public:
foobar()
{
i = 100;
}
void inc()
{
i++;
}
};
foobar foo;
int main()
{
foo.inc();
for (;;);
}
Run Code Online (Sandbox Code Playgroud)
我这样编译:
arm-none-eabi-g++ -O0 -gdwarf-2 -mcpu=cortex-m3 -mthumb -c foo.cpp -o foo.o
Run Code Online (Sandbox Code Playgroud)
当我用objdump查看.init_array部分时,它显示.init_section的大小为零.
我得到一个名为的符号_Z41__static_initialization_and_destruction_0ii.当我反汇编目标文件时,我看到全局构造是在static_initialization_and_destruction符号中完成的.
为什么.init_section中没有将指针添加到此符号?
Tre*_*son 26
我知道问题已经差不多两年了,但我只是想弄清楚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
...
Run Code Online (Sandbox Code Playgroud)
当我查看部分内容时,它只包含0:
$ arm-none-eabi-objdump -j .init_array -s foo.o
Contents of section .init_array:
0000 00000000 ....
Run Code Online (Sandbox Code Playgroud)
但是,还有一个重定位部分将其正确设置为_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
Run Code Online (Sandbox Code Playgroud)
通常,.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)();
}
}
Run Code Online (Sandbox Code Playgroud)
__init_array_start并__init_array_end通过链接脚本定义:
. = ALIGN(4);
.init_array :
{
__init_array_start = .;
KEEP (*(.init_array*))
__init_array_end = .;
}
Run Code Online (Sandbox Code Playgroud)
这种方法似乎适用于CodeSourcery交叉编译器和本机ARM GCC,例如在Ubuntu 12.10 for ARM中.支持两个编译器是使用-nostdlib而不是依赖CodeSourcery CS3裸机支持的一个原因.
由于 gcc 的 -c 参数,您只生成了一个目标文件。要创建 .init 部分,我相信您需要将该 .o 链接到实际的可执行文件或共享库中。尝试删除 -c 参数并将输出文件重命名为“foo”,然后使用反汇编程序检查生成的可执行文件。
| 归档时间: |
|
| 查看次数: |
8636 次 |
| 最近记录: |