我知道問了這個問題已經差不多兩年了,但我只是想弄清楚自己用GCC進行裸機C++初始化的機制,所以我想我會在這裏分享細節。網絡上出現了很多過時或令人困惑的信息。例如,經常提到的collect2
包裝似乎不適用於ARM ELF目標,因爲它的任意部分支持啓用了下述方法。
首先,當我編譯上面使用的Sourcery Codebench完成精簡版2012.09-63給定的命令行的代碼,但我看到了4正確.init_array
斷面尺寸:
$ 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裸機支持的一個原因。
你不認爲gcc足夠聰明1)看到值是100或2)看到該值只是遞增但從來沒有使用? – 2011-06-14 17:34:35
@波佩爾森:這就是爲什麼我添加-O0選項,所以海灣合作委員會不會優化。 – 2011-06-15 07:20:39