.bss
セクションは、プログラムがメモリにロードされたときにすべてゼロになることが保証されています。したがって、初期化されていない、またはゼロに初期化されたグローバルデータは、.bss
セクションに配置されます。たとえば:
static int g_myGlobal = 0; // <--- in .bss section
この程度の素敵な部分があり、.bss
セクションデータはディスク上のELFファイル(すなわちに含まれていなくてもゼロの領域全体がためにファイルにありません。 .bss
セクション)。代わりに、ローダーはセクションヘッダから、.bss
セクションにどれだけ割り当てるべきかを知っていて、プログラムに制御を渡す前にそれをゼロにするだけです。
お知らせreadelf
出力:
[ 3] .data PROGBITS 00000000 000110 000000 00 WA 0 0 4
[ 4] .bss NOBITS 00000000 000110 000000 00 WA 0 0 4
.data
はPROGBITS
としてマークされています。これは、ローダーがあなたのためにメモリに読み出す必要があるELFファイルにプログラムデータの「ビット」があることを意味します。一方、.bss
にはNOBITS
というマークがついています。つまり、ロードの一部としてメモリに読み込む必要があるファイルには何もありません。
例:
// bss.c
static int g_myGlobal = 0;
int main(int argc, char** argv)
{
return 0;
}
今、私たちはシンボルテーブルに私達の変数を探し$ readelf -S bss
Section Headers:
[Nr] Name Type Addr Off Size ES Flg Lk Inf Al
[ 0] NULL 00000000 000000 000000 00 0 0 0
:
[13] .text PROGBITS 080482d0 0002d0 000174 00 AX 0 0 16
:
[24] .data PROGBITS 0804964c 00064c 000004 00 WA 0 0 4
[25] .bss NOBITS 08049650 000650 000008 00 WA 0 0 4
:
とセクションヘッダで$ gcc -m32 -Xlinker -Map=bss.map -o bss bss.c
表情でそれをコンパイルします:$ readelf -s bss | grep g_myGlobal
37: 08049654 4 OBJECT LOCAL DEFAULT 25 g_myGlobal
我々はセクションヘッダに戻ってみるとg_myGlobal
は、セクション25の一部であることが示されていることに注意してください、私たちは25が.bss
であることがわかります。
あなたの本当の質問に答えるために:
をここで上記のプログラムでは、私は、任意の非intialisedデータを持っていけないが、BSSは、8つのバイトを占有しています。なぜ8バイトを占有するのですか?
私の例を続けると、私たちはセクション25に任意のシンボルを探します。
$ readelf -s bss | grep 25
9: 0804825c 0 SECTION LOCAL DEFAULT 9
25: 08049650 0 SECTION LOCAL DEFAULT 25
32: 08049650 1 OBJECT LOCAL DEFAULT 25 completed.5745
37: 08049654 4 OBJECT LOCAL DEFAULT 25 g_myGlobal
3列目はサイズです。予想される4バイトのg_myGlobal
と、この1バイトのcompleted.5745
が表示されます。これはおそらく、Cランタイム初期化のどこかの関数静的変数です.main()
が呼び出される前に、多くの「もの」が発生することに注意してください。
4 + 1 = 5バイトです。しかし、.bss
セクションヘッダーを振り返ってみると、最後の列が4であることがわかります。これはセクションの配置です。このセクションがロードされると、常に4バイトの倍数になります。次の倍数は5から8倍であるため、.bss
セクションは8バイトです。
さらに
我々は最終的な出力でどこに置いてしまったものをオブジェクトファイルを参照するために、リンカによって生成されたマップファイルを見ることができます。
.bss 0x0000000008049650 0x8
*(.dynbss)
.dynbss 0x0000000000000000 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crt1.o
*(.bss .bss.* .gnu.linkonce.b.*)
.bss 0x0000000008049650 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crt1.o
.bss 0x0000000008049650 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crti.o
.bss 0x0000000008049650 0x1 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/32/crtbegin.o
.bss 0x0000000008049654 0x4 /tmp/ccKF6q1g.o
.bss 0x0000000008049658 0x0 /usr/lib/libc_nonshared.a(elf-init.oS)
.bss 0x0000000008049658 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/32/crtend.o
.bss 0x0000000008049658 0x0 /usr/lib/gcc/x86_64-redhat-linux/4.7.2/../../../../lib/crtn.o
また、第3列はサイズです。
.bss
の4バイトが/tmp/ccKF6q1g.o
から来ています。この簡単な例では、bss.cファイルのコンパイル時の一時オブジェクトファイルであることがわかりました。他の1バイトはcrtbegin.o
からのもので、これはCランタイムの一部です。私たちは、この1つのバイトの謎のBSS変数がcrtbegin.o
からであり、それがcompleted.xxxx
という名前ですが、それは本当の名前だということを知っているので、
は最後に、completed
あり、それはおそらく、いくつかの関数内で静的です。crtstuff.c
を見ると、static _Bool completed
が__do_global_dtors_aux()
の内側にあります。
Cでは、ポインタは%pで出力され、引数は '(void *)'にキャストされます。 – Jens
「リンクされているライブラリにもデータがありますが、私はどのような非初期化データも持っていませんが、BSSは8バイトを占有しています。実際、あなたのプログラムはローカル変数とリテラルだけを持っているので、 'data'と' bss'セクションはすべてライブラリから来ていると思います。 –