2013-02-12 41 views
5

我想了解更多關於可執行文件的「常見」部分,並且我注意到,在編譯代碼上執行objdump時,我可以看到變量僅放置在對象文件(*.o)上的通用代碼中,而不是可執行文件中。爲什麼公共部分變量只顯示在目標文件中而不是可執行文件?

這是爲什麼?

//test.c 

int i[1000]; 
int main(){return 0;} 

構建命令:

> gcc -g0 -fcommon -c test.c 
> gcc -g0 -fcommon test.c 

objdump顯示i在符號表中的共同部分:

> objdump -x test.o 
    ... 
    SYMBOL TABLE: 
    ... 
    00000fa0 O *COM* 00000020 i 

除非我的可執行文件運行它:

> objdump -x a.out 
    ... 
    SYMBOL TABLE: 
    ... 
    0804a040 g O .bss 00000fa0 i 

如果我使用-fno-common標誌重建目標文件,它將顯示在.bss段中,就像它在可執行文件中所做的一樣。最終的可執行文件沒有這個「常見」部分?

回答

6

公共部分是鏈接器知道的東西。它基本上把所有的common內容放入[一個典型的]可執行文件(代碼或文本,數據,bss - 有時候還有一個rodata)的三個或四個實際部分之一。

因此,在這種情況下,您的變量以.bss結尾,因爲它們未被初始化。

從gcc手冊上-fcommon/-fno-common

在C代碼,控制未初始化的全局變量的放置。 Unix C編譯器通過將變量 放置在一個公共塊中,傳統上允許在不同編譯單元中使用這些變量的多重定義。這是-fcommon指定的行爲,在大多數目標上GCC的默認值爲 。另一方面,ISO C不需要此行爲 ,並且在某些目標上可能會在變量引用上承載速度或 代碼大小懲罰。 -fno-common選項 指定編譯器應將未初始化的全局變量 放置在目標文件的數據部分,而不是 將它們生成爲公共塊。這樣做的結果是,如果在兩個不同的編譯中聲明瞭相同的 變量(不帶extern),則在鏈接它們時會出現多重定義錯誤。在這種情況下, 您必須使用-fcommon進行編譯。使用-fno-common進行編譯是 對於其提供更好性能的目標很有用,或者如果您想驗證該程序是否可以在其他系統上工作,而其他系統始終使用 以這種方式處理未初始化的變量聲明。

所以,-fno-common-fcommon只會有所作爲,如果有不止一個叫i [他們應該是相同大小的全局變量,或者你的程序變爲無效,這是一個等級高於未定義行爲更差!]

+0

好的......那麼共同部分是什麼意思呢?同時使用'fcommon'和'fno-common'的最終結果是未初始化的變量以可執行文件的.bss段結束;或者它存在的原因與你寫''[典型的]''相同?這意味着也有例外 – Mike 2013-02-12 19:32:09

+2

@Mike但是編譯器並不知道這個 - 它是連接器的工作,以解決這個問題。對於提供.bss段的目標(和可執行格式),bss段通常在運行時分配和初始化。在沒有這種能力的目標上,通用部分最終在可執行文件中,如果你有一個10Mb的全局數組,那麼你的可執行文件最終會變成10Mb。這也允許您編寫自己的鏈接器腳本,並將這些常用部分放在您想要的地方。 -fno-common有其他用途,但是gcc手冊頁解釋了它。 – nos 2013-02-12 19:35:28

+0

我說「一個典型」,因爲可以在某些體系結構中添加額外的部分,並且這些部分也可以分配所有方式的屬性。並不是所有的編譯器,鏈接器等都可以支持這個功能,'gcc'能夠在大量系統上運行,並且擁有大量的操作系統架構。我不希望有人在操作系統glurf上指出,在鏈接器X中,有部分叫做......等。 – 2013-02-12 19:41:55

相關問題