8

「 Unix の bss セグメントとデータ セグメントについて」という質問への回答の 1 つに、 bssに関する次のような説明があります。

Bss は特別です。.bss オブジェクトはオブジェクト ファイル内でスペースを取りません。特に初期化されていないすべてのシンボルをグループ化することで、一度に簡単にゼロにすることができます。

しかし、コードから生成されたオブジェクト ファイルで size を使用すると、次のようになります。

#include <stdio.h>
int uninit_global_var;
int init_global_var=5;

int main()
{
   int local_var;
   return 0;
}

私は次のものを持っています

text    data      bss    dec     hex filename
1231     280      12    1523     5f3 a.out

グローバル スコープを持つ初期化されていないデータ メンバーに基づいて bss が成長するのを確認します。それで、誰でも言及された声明を正当化できますか?

4

4 に答える 4

9

stdio.h を削除すると、おそらく出力がより意味のあるものになります。内部変数が含まれているため、そのライブラリを無視しましょう。

特定のケースでは、次のことが起こります。

int uninit_global_var;

これはファイルスコープで割り当てられた変数であるため、として宣言された変数と同様に、静的ストレージ期間staticがあります。C 標準では、この場合のように、静的ストレージ期間を持つ変数がプログラマーによって明示的に初期化されていない場合、プログラムを開始する前にゼロに設定する必要があります。そのような変数はすべて.bssセグメントに入れられます。

int init_global_var=5;

この変数はファイル スコープでも割り当てられるため、静的な保存期間もあります。ただし、この場合、プログラマによって初期化されます。C 標準では、プログラムを開始する前に、そのような変数を指定された値に設定する必要があります。このような変数は.dataセグメントに配置されます。

   int local_var;

この変数には、自動保存期間 (ローカル) があります。この変数は目的を果たさないため、コンパイラはおそらくこの変数を最適化して取り除きます。しかし、そのような最適化が行われないと仮定しましょう。変数は、それが存在するスコープ (ブロック) が実行されるときに実行時に割り当てられ、そのスコープが終了すると (スコープ外になる) 存在しなくなります。スタックまたは CPU レジスタに割り当てられます。つまり、リンク時に、この変数はプログラム コードとしてのみ存在し、「スタックに int をプッシュ」し、後で「スタックから int をポップ」するアセンブラ命令の形式で存在します。

これらの異なる種類の変数がどのように初期化されるかは、システムによって異なります。ただし、通常、main が呼び出される前に、コンパイラによって挿入されるコードがいくつかあります。これは単純化しすぎていますが、教育学のために、プログラムは実際には次のようになっていると想像できます。

bss
{
  int uninit_global_var;
}

data
{
  int init_global_var;
}

rodata
{
  5;
}


int start_of_program (void) // called by OS
{
  memset(bss, 0, bss_size);
  memcpy(data, rodata, data_size);

  return main(); 
}

データ:4 bss:4

真の不揮発性メモリを備えた組み込みシステムは上記のコードとまったく同じように動作しますが、RAM ベースのシステムはデータの初期化部分を異なる方法で解決する場合があります。bss はすべてのシステムで同じように機能します。


次のプログラムを実行すると、それらが異なるセグメントに格納されていることを簡単に確認できます。

char uninit1;
char uninit2;
char init1 = 1;
char init2 = 2;

int main (void)
{
  char local1 = 1;
  char local2 = 2;

  printf("bss\t%p\t%p\n", &uninit1, &uninit2);
  printf("data\t%p\t%p\n", &init1, &init2);
  printf("auto\t%p\t%p\n", &local1, &local2);
}

「uninit」変数が隣接するアドレスに割り当てられていることがわかりますが、他の変数とは異なるアドレスにあります。「init」変数と同じです。「ローカル」変数はどこにでも割り当てることができるため、これら2つの結果として、あらゆる種類の奇妙なアドレスを取得できます。

于 2012-10-09T11:48:02.800 に答える
6

正確な答えはわかりませんが、私の知識に基づいた推測は次のとおりです。

bss セグメントの SIZE はオブジェクト ファイルにあり、サイズで示されます -> 結局、それを割り当てる必要があります。

しかし、bss セグメントが大きくなっても、オブジェクト ファイルは大きくなりません。

于 2012-10-09T10:57:31.903 に答える
2

bss セグメントは大きくなりますが、バイナリにこのセグメントは必要ありません (objcopy を参照)。

したがって、最終的にこのコードをある種の ROM に配置する場合、そこにスペースは必要ありませんが、RAM にスペースが必要になります (およびそれを 0 に初期化するコード)。

于 2012-10-09T11:56:33.707 に答える
2

a.outおそらくオブジェクト ファイルではなく、おそらく ELF (完全な実行可能ファイル) です。一般にname .oという名前の再配置可能オブジェクトは、リンクが発生する前の中間ファイルです。gcc の -c オプションを参照してください。

于 2012-10-09T10:58:04.260 に答える