私が知っているのは、グローバル変数と静的変数は.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 ?** */
}
その理由は、プログラムのサイズを小さくするためです。 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は非常に効率的なインラインアセンブラである可能性が高いため、スタートアップコピーダウンをより高速に実行できます。
_.bss
_セグメントは最適化です。 _.bss
_セグメント全体は、おそらく4バイトまたは8バイトの単一の数字で記述され、実行中のプロセスでそのサイズを示しますが、_.data
_セクションは初期化されたサイズの合計と同じ大きさです。変数。したがって、_.bss
_を使用すると、実行可能ファイルのサイズが小さくなり、ロードが速くなります。そうでない場合、変数は_.data
_セグメント内にあり、明示的にゼロに初期化されます。プログラムは違いを見分けるのが難しいでしょう。 (詳細には、_.bss
_のオブジェクトのアドレスは、_.data
_セグメントにある場合のアドレスとはおそらく異なるでしょう。)
最初のプログラムでは、a
は_.data
_セグメントにあり、b
は実行可能ファイルの_.bss
_セグメントにあります。プログラムがロードされると、区別は重要ではなくなります。実行時に、b
は20 * sizeof(int)
バイトを占有します。
2番目のプログラムでは、var
にスペースが割り当てられ、main()
の割り当てによってそのスペースが変更されます。 var
のスペースが_.bss
_セグメントではなく_.data
_セグメントに記述されていることがありますが、実行時のプログラムの動作には影響しません。
アセンブリ言語のステップバイステップ:Linuxでのプログラミング Jeff Duntemannによる。dataセクションに関して:
。dataセクションには、初期化されたデータ項目のデータ定義が含まれます。初期化データは、プログラムの実行が開始される前に値を持つデータです。これらの値は、実行可能ファイルの一部です。実行可能ファイルが実行のためにメモリにロードされると、それらはメモリにロードされます。
.dataセクションについて覚えておくべき重要なことは、定義する初期化されたデータ項目が多いほど、実行可能ファイルが大きくなり、実行時にディスクからメモリにロードするのに時間がかかることです。
および。bssセクション:
プログラムの実行を開始する前に、すべてのデータ項目に値を設定する必要はありません。たとえば、ディスクファイルからデータを読み取る場合、データがディスクから入った後に移動するための場所が必要です。そのようなデータバッファは、プログラムの。bssセクションで定義されています。バッファにいくつかのバイト数を確保し、バッファに名前を付けますが、バッファにどの値が存在するかは言いません。
.dataセクションで定義されたデータ項目と.bssセクションで定義されたデータ項目の間には、決定的な違いがあります。dataセクションのデータ項目は、実行可能ファイルのサイズに追加されます。 .bssセクションのデータ項目はそうではありません。 16,000バイト(またはそれ以上、場合によってはそれ以上)を占めるバッファーを.bssで定義し、実行可能ファイルのサイズにほとんど何も追加しません(説明では約50バイト)。
まず、この例の変数は初期化されていません。 Cは、他の方法では初期化されない静的変数が0に初期化されることを指定します。
そのため、.bssの理由は、実行可能ファイルを小さくし、スペースを節約し、プログラムのロードを高速化できるようにすることです。ローダーは、ディスクからデータをコピーする代わりにゼロの束を割り当てるだけです。
プログラムを実行すると、プログラムローダーは.dataと.bssをメモリにロードします。したがって、.dataまたは.bssにあるオブジェクトへの書き込みはメモリにのみ行われ、ディスク上のバイナリにフラッシュされることはありません。
Wikipediaの記事 。bss は、用語が1950年代半ば(yippee私の誕生日) ;-)。
昔は、すべてのビットが貴重だったため、予約済みの空きスペースを通知する方法はどれも便利でした。これ(。bss)は、スタックしているものです。
。dataセクションは空ではないスペース用であり、むしろ(あなたの)定義された値が入力されます。
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