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) }
沒有留言:
張貼留言