.bssセクションのゼロで初期化された変数は、elfファイルのスペースを占有しますか?

StackOverflow https://stackoverflow.com/questions/610682

  •  03-07-2019
  •  | 
  •  

質問

正しく理解できれば、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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top