#include <stdio.h> extern int __bss_start, _end; int a, b, c, d; /* un-initialized */ int main() { int *ptr; a = 1, b = 2, c = 3, d = 4; for (ptr = &__bss_start; ptr != &_end; ptr++) { printf("%d\n", *ptr); } return 0; }為行文便利,此小程式命名為 [bss.c],咱們就先試著執行看看。在筆者的電腦安裝有 gcc 3.4 與 4.3 兩個版本,先用 gcc-3.4 看看:
$ gcc-3.4 -xc bss.c && ./a.out 0 4 1 2 3由上可見,C 語言程式碼中的 int a, b, c, d 在宣告的時候,並未給定數值,也就是「未作初始化」,這樣的變數在 ELF 的角度來看,就存放於 .bss section,而在 main() 中,這四個變數都在執行時期 (runtime) 被給定數值,上述的程式透過迴圈,將給定的 1, 2, 3, 4 等值都印列出來 (儘管順序不是預期的遞增排列,不過本文不會深入分析),這是怎麼做到的呢?關鍵之處就在於一開始宣告的這行:
extern int __bss_start, _end;注意到此行前方的 "extern" 關鍵字,在 GNU Toolchain 會對名稱為 "__bss_start" 與 "_end" 的符號作特別處理,在預設的 linker script 中,會給定輸出 ELF 執行檔的 .bss section 的資訊,重點是,經過這樣的操作後,"__bss_start" 與 "_end" 只是 label 而非真正的變數,所以,並不佔用真正的記憶體空間。在 C 語言中,我們可取得其位址作指標的尋訪過程,以逐一得知 .bss section 各元素的內容值,這下似乎明暸了,但回顧剛剛的執行輸出,我們不免對其中的 "0" 感到困惑,是啊,這值到底從哪邊來?
$ gcc-4.3 -xc bss.c && ./a.out 0 0 4 1 2 3感覺起來就更離奇了,「又」多了一個 "0" 的輸出?!看來是 GNU Toolchain 對 ELF 執行檔額外施加了「魔法」,看來得搬出其他工具來分析。先觀察 objdump 對 .bss section 的分析:
$ gcc-3.4 -xc bss.c && objdump --section=.bss -x a.out ... SYMBOL TABLE: 08049598 l d .bss 00000000 .bss 08049598 l O .bss 00000001 completed.1 0804959c g O .bss 00000004 d 080495a0 g O .bss 00000004 a 080495a4 g O .bss 00000004 b 080495a8 g O .bss 00000004 c可以發現,事實上程式碼的 &__bss_start 勢必指向 ELF 執行檔透過 Program Loader 映射到記憶體中的 BSS 區域,而我們在程式中尋訪 .bss section 中的元素,大抵就是依照上面的 SYMBOL TABLE 的排列方式,而之前那個印列出的 "0" 數值,就是 "completed.1" 這個符號的內含值。同理,我們觀察透過 gcc-4.3 編譯時的分析結果:
$ gcc-4.3 -xc bss.c && objdump --section=.bss -x a.out ... SYMBOL TABLE: 0804a014 l d .bss 00000000 .bss 0804a014 l O .bss 00000001 completed.6625 0804a018 l O .bss 00000004 dtor_idx.6627 0804a01c g O .bss 00000004 d 0804a020 g O .bss 00000004 a 0804a024 g O .bss 00000004 b 0804a028 g O .bss 00000004 c在這份輸出中,我們看到形似剛剛 "completed.1" 的 "completed.6625" 符號,也多了名稱為 "dtor_idx.6627" 的符號。為了揭開謎團的真相,筆者又用 gcc-4.1 與 gcc-4.2 作實驗,這兩者得到與 gcc-3.4 編譯時相仿的輸出,但 "completed." 符號後方的數值名稱是不一樣的,由此可歸納,gcc-4.3 引入了一些我們未察覺的修改,而在 gcc-3.4 到 gcc-4.2 之間的 GNU Toolchain 所編譯的 ELF 執行檔,其 .bss section 也隱含我們不甚明暸的細節。
非常好奇为什么“順序不是預期的遞增排列”,请指教,谢谢!
由 Wei 發表於 June 20, 2008 02:10 AM我猜順序是因為 parse tree 之 traverse 的關係?
由 c9s 發表於 June 22, 2008 01:59 AM