共通ブロックの配列をいじってみました。Linux の .bss セグメントは、実際にはヒープとマージされているように見えます (または、少なくとも同じbrk(2)
メカニズムを使用してスペースが割り当てられています)。
関連する Fortran コードは次のとおりです。
double precision u(5,20,20,20)
common /a/ u
gfortran
生成される GNU アセンブリ ディレクティブは次のとおりです。
.comm a_,320000,32
a_
これは、320000 バイトの大きさで、32 バイト境界に配置する必要があるという名前の共通シンボルを宣言します。リンカーがこの宣言を認識し、他の定義がないa_
場合、.bss にスペースが予約されます。これはobjdump
、結果のバイナリで実行することから明確にわかります。
Sections:
Idx Name Size VMA LMA File off Algn
...
22 .data 00000010 0000000000600b40 0000000000600b40 00000b40 2**3
CONTENTS, ALLOC, LOAD, DATA
23 .bss 0004e220 0000000000600b60 0000000000600b60 00000b50 2**5
ALLOC
...
ここで、.bss は 320000 (0x4e200) バイトと 32 バイトの追加データです。割り当て可能としてマークされるだけで、それ以上のことはありません。ファイルからデータが事前入力されることはありません。また、VMA 0x600b80 で始まるa_
ため、32 バイトの追加データが前に置かれていると推測できます。u
(gdb) info address u
Symbol "u" is static storage at address 0x600b80.
(gdb) info symbol &u
a_ in section .bss of /path/to/a.out
u
は実際には Fortran のメイン関数のローカル変数のシンボルにすぎませんa_
が、 はグローバルに可視なストレージです。そのため、異なるサブルーチン/関数で配列に異なる名前を付けることができますが、それらを適切な共通ブロックに配置すると、同じメモリにアクセスできます。
.bss の厄介な VMA は、.bss がメモリ内の .data セクションの直後に配置されているため、ELF ファイル内の .data セグメントのオフセットの結果であるように見えます。.data セグメントが Linux にロードされる方法は、マッピングにコピー オン ライト セマンティクスを与えるmmap(2)
ファイルから -ed されることです。MAP_PRIVATE
00400000-00401000 r-xp 00000000 00:1d 25681168 /path/to/a.out
00600000-00601000 rw-p 00000000 00:1d 25681168 /path/to/a.out <-- .data
00601000-00670000 rw-p 00000000 00:00 0 [heap]
.bss は .data マッピングと同じページで始まります。これは、両方が読み取り/書き込みデータを保持し、書き込まれることが予想され、別のページで .bss を開始しないことで VM のビットが節約されるため、理にかなっています。
.data セグメントの後のすべては、ファイル マッピングによってバックアップされないため、 のように表示される動的に調整可能なスペースに収まり[heap]
ます/proc/pid/maps
。このスペースとヒープ自体は、データ セグメントの末尾を移動することによって制御されます。これはいわゆるプログラム ブレークと呼ばれbrk(2)
ます。strace
カーネルの ELF ローダーは、実行可能ファイルで確認できるように、最初にプログラム ブレークを .bss 用のスペースを確保するのに十分な距離まで移動します。
execve("./a.out", ["a.out"], [/* 230 vars */]) = 0
brk(0) = 0x64f000 <-- already moved past the .bss
.data セグメントが 00600000 で始まることがわかっています。.bss は 00600B60 で始まります。共通ブロックは 0x600b80 に割り当てられ、そのサイズは 0x4e200 であるため、0x64ed80 で終了し、ページ境界に切り上げられて 0x64f000 になります。ここで、他の動的にリンクされたライブラリが独自にスペースを割り当てない場合、実際のプログラム ヒープが開始されます。
動的メモリ アロケータmalloc(3)
は同じbrk(2)
メカニズム (mmap(2)
大規模な割り当ての場合、またはデータ セグメント サイズの制限に達した場合は匿名) を使用するため、配列が .bss にあったか、.bss で割り当てられたかは問題ではありませんALLOCATE()
。違いは、.bss が最初にゼロで埋められ、malloc
またはによって割り当てられたメモリの内容ALLOCATE()
がそのまま残されることです。