2012年6月8日 星期五

ELF中的.bss section和COMMON section

大家都知道未初始化的global變數會被配置在.bss section中。不過在ELF中沒有這麼簡單,ELF多了一個COMMON section專門用來存放未初始化的global變數。怎麼會有兩個地方都用來存放未初始化的global變數呢?其實是有差別的,以下我們舉個例子來說明:
int a = 1;            //.data section
int b = 0;            //.bss section
int c;                //COMMON section
由上面例子可以知道,如果我們把global變數初始化為非0的值,會被放在.data section。如果把global變數初始化為0,會被直接放到.bss section。如果完全沒初始化的話就會被放到COMMON section。為什麽要多一個COMMON section呢?其實跟gcc linker的運作有關係。

以上面例子為例,global變數c其實是一個弱型別。也就是說,如果我們在不同的檔案中都宣告global變數c而沒有初始化的話,gcc linker在做linking時後並不會產生error。
//test1.c
int c;

//test2.c
int c;
上面例子是完全合法的,我們也可以定義一個強型別來把弱型別蓋掉。
//test1.c
int c;

//test2.c
int c;

//test3.c
int c = 1;    //strong type
上面例子gcc linker在做linking時候如果讀到test1.c中的int c,linker會先把c放到COMMON section中。讀到test2.c的c時,因為發現重複定義,所以不會做處理。讀到test3.c中的c由於是強型別,因此會把之前在COMMON的c蓋掉,在.data section建立一個初始值為1的c。因次最後的結果我們只會在.data section中找到c這個變數,不會在COMMON中看到c這個變數。

當然如果同時定義兩個強型別變數的話,Linker就會跟你抗議了。
//test1.c
int c = 1;    //strong type

//test2.c
int c = 2;    //strong type
test2.o:(.data+0x0): multiple definition of `c'
test1.o:~/sway/test1.c:4: first defined here
collect2: ld returned 1 exit status
由上面這些例子可以知道,COMMON其實主要的用途是用來讓linker做merge用的。因此uninitialized的global變數會被暫時放在COMMON section,等Linker做完merge之後再看情況搬到正確的section中,也可能繼續留在COMMON section。因為這種特性,大多數embedded project的linker script檔都會把COMMON section放在.bss裡頭。這樣當程式啟動時可以一併把COMMON也清為0。
.bss { *(.bss) *(COMMON) }

沒有留言:

張貼留言