.bss section 的觀念:執行時期的長度

jollen 發表於 December 15, 2006 2:02 AM

在「理解 dynamic loader 內部原理的幾個先備知識(一)」講到:.bss 節區「linking view」上不佔檔案空間。這點可以用 readelf 來做 ELF linking view 端的印證:

# readelf -e bss|more  (bss 是我們的範例執行檔)
...
Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .interp           PROGBITS        080480f4 0000f4 000013 00   A  0   0  1
  [ 2] .note.ABI-tag     NOTE            08048108 000108 000020 00   A  0   0  4
  [ 3] .hash             HASH            08048128 000128 000028 04   A  4   0  4
  [ 4] .dynsym           DYNSYM          08048150 000150 000050 10   A  5   1  4
  [ 5] .dynstr           STRTAB          080481a0 0001a0 00004c 00   A  0   0  1
  [ 6] .gnu.version      VERSYM          080481ec 0001ec 00000a 02   A  4   0  2
  [ 7] .gnu.version_r    VERNEED         080481f8 0001f8 000020 00   A  5   1  4
  [ 8] .rel.dyn          REL             08048218 000218 000008 08   A  4   0  4
  [ 9] .rel.plt          REL             08048220 000220 000010 08   A  4   b  4
  [10] .init             PROGBITS        08048230 000230 000017 00  AX  0   0  4
  [11] .plt              PROGBITS        08048248 000248 000030 04  AX  0   0  4
  [12] .text             PROGBITS        08048278 000278 0001b8 00  AX  0   0  4
  [13] .fini             PROGBITS        08048430 000430 00001b 00  AX  0   0  4
  [14] .rodata           PROGBITS        0804844c 00044c 000031 00   A  0   0  4
  [15] .eh_frame         PROGBITS        08048480 000480 000004 00   A  0   0  4
  [16] .data             PROGBITS        08049484 000484 00000c 00  WA  0   0  4
  [17] .dynamic          DYNAMIC         08049490 000490 0000c8 08  WA  5   0  4
  [18] .ctors            PROGBITS        08049558 000558 000008 00  WA  0   0  4
  [19] .dtors            PROGBITS        08049560 000560 000008 00  WA  0   0  4
  [20] .jcr              PROGBITS        08049568 000568 000004 00  WA  0   0  4
  [21] .got              PROGBITS        0804956c 00056c 000018 04  WA  0   0  4
  [22] .bss              NOBITS          08049584 000584 00000c 00  WA  0   0  4
  [23] .comment          PROGBITS        00000000 000584 000132 00      0   0  1
...

重點的部份我用粗體字標示出來了:.bss section 與 .comment section 在檔案裡的 offset 是相同的。不過,用「他人」的工具來印可能會有一些盲點存在,比如說,我們可能不是很明白「Off」真正的意義;建議使用我們自行撰寫的 ELF 讀檔程式 loader-0.5.c(下載)來做,因為這是自己寫的工具,能保證一些盲點都能得到證明。以下是用 loader-0.5.c 印出來的畫面:

# ./loader bss
ELF Identification
  Class:        32-bit objects
Machine:        Intel 80386
Name                Size FileOff
[00] .interp               19     244
[01] .note.ABI-tag         32     264
[02] .hash                 40     296
[03] .dynsym               80     336
[04] .dynstr               76     416
[05] .gnu.version          10     492
[06] .gnu.version_r        32     504
[07] .rel.dyn               8     536
[08] .rel.plt              16     544
[09] .init                 23     560
[10] .plt                  48     584
[11] .text                440     632
[12] .fini                 27    1072
[13] .rodata               49    1100
[14] .eh_frame              4    1152
[15] .data                 12    1156
[16] .dynamic             200    1168
[17] .ctors                 8    1368
[18] .dtors                 8    1376
[19] .jcr                   4    1384
[20] .got                  24    1388
[21] .bss                  12    1412
[22] .comment             306    1412

了解 ELF 並自己撰寫工具,此過程讓我們了解到「Offset」指的是「確實是該 section 在檔案裡的啟始讀取位置」。這代表,無論程式裡有多少 uninitialized data,都是不佔用額外的檔案空間的。

畫面中的節區大小

「Size」代表該 section 的實體大小(in bytes),以 .bss section 來說,.bss section 的大小是 12 bytes。很不幸的是,這個大小並非表示 .bss section 佔用的「檔案大小」,而是「記憶體大小」;這可能會是一個使用工具時,因為畫面的「字義」所不小心產生的盲點。所以如果把 .bss section 的 Offset 加上他的 Size,並不會等於 .comment section 的 Offset

所謂的「Size」,包含由 objdumpreadelf 所列印出來的畫面,或者說,「紀載在 section header entry」裡的 size 資訊,是表示「該 section 的實體記憶體大小」。

.bss section 的長度計算方式

.bss 的大小計算方式為(IA32 平臺):

4 bytes + sizeof(所有的 uninitialized data)

這代表 .bss section 在記憶體所會佔用的長度。以先前的例子來說,計算式會是:

4 + sizeof(foo) + sizeof(bar) = 4 + 4 + 4 = 12 (bytes)

所以,.bss section 的「size」field 就是 12。

.bss section 的結構

.bss section 的空間結構類似於 stack,所以前一則日記講述的「foo 是第一個 uninitialized data,所以他的 virtual address,形同 .bss section 的開始位址(process virtual address)。」觀念,並非全然正確

此部份留待後續再做說明。

Also See

Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue

您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw