2011-06-14 15 views
9

我想在嵌入式目標(ARM Cortex-M3)上添加全局構造函數支持。 可以說,我已經下面的代碼:全局構造函數調用不在.init_array部分

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_section具有零大小.init_array節。

我確實收到了一個名爲_Z41__static_initialization_and_destruction_0ii的符號。 當我反彙編目標文件時,我發現全局構造是在static_initialization_and_destruction符號中完成的。

爲什麼在.init_section中沒有將指針添加到此符號中?

+0

你不認爲gcc足夠聰明1)看到值是100或2)看到該值只是遞增但從來沒有使用? – 2011-06-14 17:34:35

+1

@波佩爾森:這就是爲什麼我添加-O0選項,所以海灣合作委員會不會優化。 – 2011-06-15 07:20:39

回答

3

由於gcc的-c參數,您只生成了一個目標文件。要創建.init部分,我相信你需要將該.o鏈接到一個實際的可執行文件或共享庫中。嘗試刪除-c參數並將輸出文件重命名爲「foo」,然後使用反彙編程序檢查生成的可執行文件。

+0

當我這樣做時,我仍然有同樣的問題。 – 2011-06-14 13:15:25

+0

好的,所以在我對ARM基本不瞭解的情況下,我會說這意味着您需要採取另一個步驟來實現對ARM的全球ctor和dtors的支持。事實上,你得到的_Z41 _...符號是令人鼓舞的,因爲它暗示.o文件是正確的。但顯然鏈接時沒有發生什麼事情。在x86 GCC上,一個名爲collect2的鏈接時間進程處理將所有各種靜態構造函數合併到.init部分,然後交給ld(或類似的東西)。我認爲鏈接器支持是您的下一步。 – acm 2011-06-14 13:32:33

2

如果你仔細看看_Z41__static_initialization_and_destruction_0ii會在全局構造函數內調用。在.init_array部分(來自CodeSourcery的arm-none-eabi-)或其他函數(如果使用的是Linux g ++,則爲__main())中將鏈接哪個inturn。 ()這應該在啓動時或在main()處調用。 另請參閱this鏈接。

23

我知道問了這個問題已經差不多兩年了,但我只是想弄清楚自己用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裸機支持的一個原因。

+2

我不知道事情自2013年2月以來是否發生了變化,但是我發現我必須將'__init_array_start'和'__init_array_end'作爲函數指針,而不是指向函數指針的指針: typedef void(* InitFunc)(void) ; extern InitFunc __init_array_start; extern InitFunc __init_array_end; InitFunc * pFunc =&__ init_array_start; (; pFunc <&__ init_array_end; ++ pFunc){ (* pFunc)(); } – Timma 2015-03-11 02:43:20

+0

@Timma,你的代碼中有幾個錯誤。它編譯時更改爲'typedef void(* InitFunc)(void); extern InitFunc __init_array_start; extern InitFunc __init_array_end; InitFunc * pFunc =&__ init_array_start; for(; pFunc <&__ init_array_end; ++ pFunc){(* pFunc)(); ''。 – lorcap 2016-12-01 14:23:35

+0

問題[理解__libc_init_array](http://stackoverflow.com/questions/15265295/understanding-the-libc-init-array)提供了一個更清晰的代碼,它使用指針數組來操作。它的工作原理。 – lorcap 2016-12-01 16:35:57

2

我有一個類似的問題,我的構造函數沒有被調用(nRF51822 Cortex-M0與GCC)。問題原來是由於此連接器標誌:

-Wl,--gc-sections 

不要問我爲什麼!我認爲它只能刪除死碼。

+0

許多很多天真的「死代碼」消除算法都會去除*未引用*的符號/節,這些符號/節不會對可達到的輸出做出貢獻* ...即使它們是中斷處理程序,靜態全局數據結構等所需的。不是gcc的工作方式,但它是一個常見的問題。嘗試在gcc和clang下的鏈接時優化'-flto -O4'來查看會發生什麼。 – Barry 2015-11-24 01:53:27

+0

它刪除死碼。如果有一個沒有人引用的全局對象,它的構造函數是否調用死代碼?實際上沒有人會調用這個對象... – dascandy 2015-12-07 09:12:23

+0

如果它有副作用,它不是死碼。 – 2016-05-10 11:30:21

4

Timmmm,

我只是在nRF51822相同的問題,並通過添加KEEP()圍繞股票北歐.LD文件中的幾行解決了這個問題:

KEEP(*(SORT(.init_array.*))) 
KEEP(*(.init_array)) 

雖然它,我也對fini_array領域也做了同樣的事情。解決了我的問題,鏈接器仍然可以刪除其他未使用的部分...