web-dev-qa-db-ja.com

なぜ.bssセグメントが必要なのですか?

私が知っているのは、グローバル変数と静的変数は.dataセグメントに格納され、初期化されていないデータは.bssセグメントに格納されるということです。私が理解していないのは、なぜ初期化されていない変数専用のセグメントがあるのですか?初期化されていない変数に実行時に値が割り当てられている場合、変数はまだ.bssセグメントにのみ存在しますか?

次のプログラムでは、a.dataセグメントにあり、b.bssセグメントにあります。あれは正しいですか?私の理解が間違っている場合は親切に修正してください。

#include <stdio.h>
#include <stdlib.h>

int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9};
int b[20]; /* Uninitialized, so in the .bss and will not occupy space for 20 * sizeof (int) */

int main ()
{
   ;
}  

また、次のプログラムを検討してください。

#include <stdio.h>
#include <stdlib.h>
int var[10];  /* Uninitialized so in .bss */
int main ()
{
   var[0] = 20  /* **Initialized, where this 'var' will be ?** */
}
106
Whoami

その理由は、プログラムのサイズを小さくするためです。 Cプログラムが組み込みシステムで実行され、コードとすべての定数がtrue ROM(フラッシュメモリ)に保存されていることを想像してください。このようなシステムでは、最初の「コピーダウン」を実行する必要がありますmain()が呼び出される前に、すべての静的ストレージ期間オブジェクトを設定します。通常、次のようになります。

for(i=0; i<all_explicitly_initialized_objects; i++)
{
  .data[i] = init_value[i];
}

memset(.bss, 
       0, 
       all_implicitly_initialized_objects);

.dataと.bssはRAMに格納されますが、init_valueはROMに格納されます。それが1つのセグメントであった場合、ROMは多くのゼロで埋め、ROMサイズを大幅に増やす必要がありました。

RAMベースの実行可能ファイルも同様に機能しますが、もちろん真のROMはありません。

また、memsetは非常に効率的なインラインアセンブラである可能性が高いため、スタートアップコピーダウンをより高速に実行できます。

79
Lundin

_.bss_セグメントは最適化です。 _.bss_セグメント全体は、おそらく4バイトまたは8バイトの単一の数字で記述され、実行中のプロセスでそのサイズを示しますが、_.data_セクションは初期化されたサイズの合計と同じ大きさです。変数。したがって、_.bss_を使用すると、実行可能ファイルのサイズが小さくなり、ロードが速くなります。そうでない場合、変数は_.data_セグメント内にあり、明示的にゼロに初期化されます。プログラムは違いを見分けるのが難しいでしょう。 (詳細には、_.bss_のオブジェクトのアドレスは、_.data_セグメントにある場合のアドレスとはおそらく異なるでしょう。)

最初のプログラムでは、aは_.data_セグメントにあり、bは実行可能ファイルの_.bss_セグメントにあります。プログラムがロードされると、区別は重要ではなくなります。実行時に、b20 * sizeof(int)バイトを占有します。

2番目のプログラムでは、varにスペースが割り当てられ、main()の割り当てによってそのスペースが変更されます。 varのスペースが_.bss_セグメントではなく_.data_セグメントに記述されていることがありますが、実行時のプログラムの動作には影響しません。

74

アセンブリ言語のステップバイステップ:Linuxでのプログラミング Jeff Duntemannによる。dataセクションに関して:

。dataセクションには、初期化されたデータ項目のデータ定義が含まれます。初期化データは、プログラムの実行が開始される前に値を持つデータです。これらの値は、実行可能ファイルの一部です。実行可能ファイルが実行のためにメモリにロードされると、それらはメモリにロードされます。

.dataセクションについて覚えておくべき重要なことは、定義する初期化されたデータ項目が多いほど、実行可能ファイルが大きくなり、実行時にディスクからメモリにロードするのに時間がかかることです。

および。bssセクション:

プログラムの実行を開始する前に、すべてのデータ項目に値を設定する必要はありません。たとえば、ディスクファイルからデータを読み取る場合、データがディスクから入った後に移動するための場所が必要です。そのようなデータバッファは、プログラムの。bssセクションで定義されています。バッファにいくつかのバイト数を確保し、バッファに名前を付けますが、バッファにどの値が存在するかは言いません。

.dataセクションで定義されたデータ項目と.bssセクションで定義されたデータ項目の間には、決定的な違いがあります。dataセクションのデータ項目は、実行可能ファイルのサイズに追加されます。 .bssセクションのデータ項目はそうではありません。 16,000バイト(またはそれ以上、場合によってはそれ以上)を占めるバッファーを.bssで定義し、実行可能ファイルのサイズにほとんど何も追加しません(説明では約50バイト)。

11
mihai

まず、この例の変数は初期化されていません。 Cは、他の方法では初期化されない静的変数が0に初期化されることを指定します。

そのため、.bssの理由は、実行可能ファイルを小さくし、スペースを節約し、プログラムのロードを高速化できるようにすることです。ローダーは、ディスクからデータをコピーする代わりにゼロの束を割り当てるだけです。

プログラムを実行すると、プログラムローダーは.dataと.bssをメモリにロードします。したがって、.dataまたは.bssにあるオブジェクトへの書き込みはメモリにのみ行われ、ディスク上のバイナリにフラッシュされることはありません。

9
janneb

Wikipediaの記事 。bss は、用語が1950年代半ば(yippee私の誕生日) ;-)。

昔は、すべてのビットが貴重だったため、予約済みの空きスペースを通知する方法はどれも便利でした。これ(。bss)は、スタックしているものです。

。dataセクションは空ではないスペース用であり、むしろ(あなたの)定義された値が入力されます。

3
Philip Oakley

System V ABI 4.1(1997)(別名ELF仕様)には答えも含まれています:

.bssこのセクションは、プログラムのメモリイメージに寄与する初期化されていないデータを保持します。定義上、プログラムの実行が開始されると、システムはデータをゼロで初期化します。セクションタイプSHT_NOBITSで示されるように、セクションはファイルスペースを占有しません。

セクション名.bssは予約されており、特別な効果があり、特にファイルスペースを占有しないため、.data

欠点はもちろん、OSがそれらをメモリに配置するときにすべてのバイトを0に設定する必要があることです。これはより制限的ですが、一般的なユースケースであり、初期化されていない変数に対しては正常に機能します。

SHT_NOBITSセクションタイプのドキュメントでは、この確認が繰り返されています。

sh_sizeこのメンバーは、セクションのサイズをバイト単位で提供します。セクションタイプがSHT_NOBITSでない限り、セクションはファイルのsh_sizeバイトを占有します。タイプSHT_NOBITSのセクションのサイズは0以外でもかまいませんが、ファイル内のスペースを占有しません。

C標準はセクションについては何も述べていませんが、変数がLinuxでobjdumpおよびreadelfを使用して保存されている場所を簡単に確認でき、初期化されていないグローバルは実際に.bss、たとえばこの回答を参照してください: https://stackoverflow.com/a/36725211/895245