全部博文(89)
分类: LINUX
2009-04-10 10:36:58
在「理解 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」,包含由 objdump 與 readelf 所列印出來的畫面,或者說,「紀載在 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)。」觀念,並非全然正確。
此部份留待後續再做說明。