.bssセクションのゼロで初期化された変数は、elfファイルのスペースを占有しますか?
質問
正しく理解できれば、ELFファイルの .bss
セクションを使用して、ゼロで初期化された変数にスペースを割り当てます。ツールチェーンはELFファイルを生成するため、私の質問: .bss
セクションには実際にすべてのゼロを含める必要がありますか?たとえば、10メガバイトのグローバルアレイを割り当てると、ELFファイルに10メガバイトのゼロが生じるため、スペースの無駄が非常に多いようです。ここで何が間違っているのですか?
解決
ELFで働いてからしばらく経ちました。しかし、私はまだこのようなものを覚えていると思います。いいえ、これらのゼロは物理的に含まれていません。 ELFファイルプログラムヘッダーを調べると、各ヘッダーに2つの数字があります。1つはファイルのサイズです。もう1つは、仮想メモリに割り当てられたときのセクションのサイズです( readelf -l ./a.out
):
Program Headers:
Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
PHDR 0x000034 0x08048034 0x08048034 0x000e0 0x000e0 R E 0x4
INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1
[Requesting program interpreter: /lib/ld-linux.so.2]
LOAD 0x000000 0x08048000 0x08048000 0x00454 0x00454 R E 0x1000
LOAD 0x000454 0x08049454 0x08049454 0x00104 0x61bac RW 0x1000
DYNAMIC 0x000468 0x08049468 0x08049468 0x000d0 0x000d0 RW 0x4
NOTE 0x000128 0x08048128 0x08048128 0x00020 0x00020 R 0x4
GNU_STACK 0x000000 0x00000000 0x00000000 0x00000 0x00000 RW 0x4
タイプ LOAD
のヘッダーは、ファイルが実行のためにロードされるときに仮想メモリにコピーされます。他のヘッダーには、必要な共有ライブラリなど、他の情報が含まれています。ご覧のとおり、 Files
と MemSiz
は、 bss
セクションを含むヘッダー(2番目の LOAD
one):
0x00104 (file-size) 0x61bac (mem-size)
このサンプルコードの場合:
int a[100000];
int main() { }
ELF仕様では、セグメントのmem-sizeがfile-sizeよりも大きい部分は、仮想メモリ内でゼロで埋められているだけです。 2番目の LOAD
ヘッダーのセグメントからセクションへのマッピングは次のようになります。
03 .ctors .dtors .jcr .dynamic .got .got.plt .data .bss
したがって、他にもいくつかのセクションがあります。 C ++コンストラクタ/デストラクタ用。 Javaでも同じです。次に、 .dynamic
セクションのコピーと、ダイナミックリンクに役立つその他のものが含まれます(これは、必要な共有ライブラリを他のものの中に含む場所だと思います)。その後、初期化されたグローバル変数とローカル静的変数を含む .data
セクション。最後に、 .bss
セクションが表示されます。このセクションには、ファイルサイズがカバーしていないため、ロード時にゼロが埋め込まれます。
ところで、 -M
リンカーオプションを使用すると、特定のシンボルがどの出力セクションに配置されるかを確認できます。 gccでは、 -Wl、-M
を使用して、オプションをリンカーに渡します。上記の例は、 a
が .bss
内に割り当てられていることを示しています。初期化されていないオブジェクトが実際には .bss
にあり、他のどこにもないことを確認するのに役立ちます:
.bss 0x08049560 0x61aa0
[many input .o files...]
*(COMMON)
*fill* 0x08049568 0x18 00
COMMON 0x08049580 0x61a80 /tmp/cc2GT6nS.o
0x08049580 a
0x080ab000 . = ALIGN ((. != 0x0)?0x4:0x1)
0x080ab000 . = ALIGN (0x4)
0x080ab000 . = ALIGN (0x4)
0x080ab000 _end = .
GCCは、古いコンパイラとの互換性のために、複数の定義エラーなしでプログラム内でグローバルを2回定義できるように、デフォルトで初期化されていないグローバルをCOMMONセクションに保持します。 -fno-common
を使用して、GCCがオブジェクトファイルに.bssセクションを使用するようにします(最終的にリンクされた実行可能ファイルに違いはありません。これは、リンカースクリプトによって制御されます。 ld -verbose
で表示します)。しかし、それはあなたを怖がらせるべきではありません、それは単に内部の詳細です。 gccのマンページを参照してください。
他のヒント
ELFファイルの .bss
セクションは、プログラムで初期化されていないが、実行時にゼロに設定されることが保証されている静的データに使用されます。違いを説明する小さな例を次に示します。
int main() {
static int bss_test1[100];
static int bss_test2[100] = {0};
return 0;
}
この場合、 bss_test1
は初期化されていないため、 .bss
に配置されます。ただし、 bss_test2
は、多数のゼロとともに .data
セグメントに配置されます。ランタイムローダーは、基本的に .bss
に予約されているスペースを割り当て、ユーザーランドコードの実行が開始される前にそれをゼロにします。
objdump
、 nm
、または同様のユーティリティを使用して違いを確認できます。
moozletoots$ objdump -t a.out | grep bss_test
08049780 l O .bss 00000190 bss_test1.3
080494c0 l O .data 00000190 bss_test2.4
これは通常、組み込み開発者が遭遇する最初の驚きの1つです...静的を明示的にゼロに初期化しないでください。ランタイムローダーが(通常)それを処理します。何かを明示的に初期化するとすぐに、実行可能イメージにデータを含めるようコンパイラー/リンカーに指示します。
.bss
セクションは実行可能ファイルに保存されません。最も一般的なセクション( .text
、 .data
、 .bss
)のうち、 .text
(実際のコード)および .data
(初期化されたデータ)はELFファイルに存在します。
それは正しいです。.bssはファイル内に物理的に存在するのではなく、ダイナミックローダーがアプリケーションプログラムに.bssセクションを割り当てるためのサイズに関する情報のみが存在します。 経験則としてのみLOAD、TLSセグメントはアプリケーションプログラムのメモリを取得し、残りはダイナミックローダーに使用されます。
静的実行可能ファイルについて、bssセクションには実行可能ファイル内のスペースも与えられます
ローダーのない組み込みアプリケーションは一般的です。
Suman