実行可能ファイルの ELF ファイルには、プログラム (セグメント) ヘッダーとセクション ヘッダーがあり、 を通じて確認できます。readelf -a
次に例を示します。
上の 2 つの図は、それぞれセクション ヘッダーとプログラム (セグメント) ヘッダーです。セグメント ヘッダーは複数のセクション ヘッダーで構成されており、プログラムをメモリにロードするために使用されることがわかります。
メモリにロードする必要があるのは、.text、.rodata、.data、.bss セクションだけですか?
セグメント内の他のすべてのセクション (例: 3 番目のセグメント内の .ctors、.dtors、.jcr) はアライメントに使用されますか?
ベストアンサー1
セクションとセグメントは完全に異なる概念です。セクションは、そこに保存されるデータのセマンティクス (つまり、それが何に使用されるか) に関係し、デバッグ目的を除いて、プログラムまたは共有ライブラリがリンクされると、実際には無関係になります。セクション ヘッダーを完全に削除 (またはランダムなゴミで上書き) しても、プログラムは動作します。
セグメント (つまりプログラム ヘッダーのロード ディレクティブ) は、カーネルやダイナミック リンカーがプログラムをロードするときに実際に参照するものです。たとえば、このケースでは 2 つのロード ディレクティブがあります。最初のディレクティブは、ファイルの最初の 4k (1 ページ) をアドレス 0x08048000 にマップし、このマッピングの最初の 0x4b8 バイトのみが実際に使用されることを示します (残りはアラインメントです)。2 番目のディレクティブは、ファイルの最初の 8k (2 ページ) をアドレス 0x08049000 にマップします。その大部分はアラインメントです。最初の 0xf14 バイトはロード ディレクティブの一部ではなく (アラインメントのみ)、無駄になります。0x08049f14 から、ファイルからマップされた 0x108 バイトが実際に使用され、別の 0x10 バイト (MemSize 0x118 に達するため) はローダー (カーネルまたはダイナミック リンカー) によってゼロで埋められます。これは 0x0804a02c (2 番目のマップ ページ) まで広がります。2 番目のマップ ページの残りは未使用/無駄です (ただし、malloc
ヒープの一部として使用するために回復できる可能性があります)。
最後に、セクション ヘッダーはまったく使用されませんが、プログラムの実行中にさまざまなセクションの内容が使用される場合があります。 および のアドレス範囲は 2 番目のロード マッピングの先頭にあるため、実行時にプログラムによってマップされ、アクセス可能であることに注意してください.ctors
( .dtors
ctor/dtor 属性を持つ C++ または "GNU C" コードが使用された場合、ランタイムの起動/終了コードは、グローバル コンストラクターとデストラクタを実行するためにそれらを使用します)。 また、 は.data
2 番目のマップされたページのアドレス 0x0804a00c から始まることにも注意してください。 これにより、再配置が適用された後 (プログラム ヘッダーの RELRO ディレクティブ)、最初のページを読み取り専用で保護できます。