Mach-O入門

ちょっと間が空いたけど、Mach-O入門の続き。今回はセグメント。

セグメント

セグメントは、ダイナミックリンカがアプリケーションをロードしたときに仮想メモリにマップされる、Mach-Oファイル中のデータの範囲と、メモリ保護の属性を定義しています。セグメントはページアラインされていて、ゼロもしくは一つ以上のセクションを含みます。
セグメントは、ディスク上で占有している以上のサイズのメモリを、実行時に使用することができます。たとえば__PAGEZEROセグメントは仮想メモリ上では1ページを占有しますが、ディスク上でのサイズは0です。なお、0で埋められるセクションは、セグメントの最後尾に配置される必要があります。
サイズを小さくするため、中間オブジェクトファイルは1つのセグメントのみを含みます。このセグメントには名前がありません。それぞれのセクションには、そのセクションが配置されるセグメントの名前が格納されていて、それに従ってリンカが最終オブジェクトファイルの適切なセグメントにセクションを配置します。
性能上の理由により、セグメントはページアラインされている必要があります。x86およびPowerPCアーキテクチャでは4096 byteです。
ヘッダおよびロードコマンドもセグメントの一種と見なされます。実行可能なファイルの場合、ヘッダおよびロードコマンドは、__TEXTセグメントの先頭に配置されます。
以下は、Xcode ToolsがMac OS Xの実行ファイルに含めるセグメントです。

__PAGEZERO

リンカは実行ファイルの先頭に__PAGEZEROセグメントを作成します。このセグメントは仮想メモリの先頭に、メモリ保護なしで配置されます。この__PAGEZEROセグメントは、そのアーキテクチャにおける仮想メモリの1ページを占有します。x86およびPowerPCでは4096 byte、16進数で表現すると、0x1000です。

__TEXT

__TEXTセグメントは、実行コードとそれ以外の読み込み専用のデータを含みます。カーネルが実行ファイルを共有メモリに直接マップできるように、リンカはこのセグメントの書き込み権限を落とします。セグメントがメモリにマップされると、すべてのプロセスからセグメントのデータを参照することが可能になります。セグメントの書き込み権限が落とされているということはまた、__TEXTセグメントによって作成されたページは、ディスクに書き戻す必要がないことを表します。カーネルがページを解放する必要があったときは、__TEXTセグメントを単に捨てることができます。そう、次に必要になったときに、ディスクからもう一度読み込めばいいのです。

__DATA

__DATAセグメントは、書き込み可能なデータを含みます。リンカはこのセグメントに読み書き権限を与えます。フレームワークや他の共有ライブラリの__DATAセグメントは、それらをリンクしたプロセスにそれぞれ論理的にコピーされます。__DATAセグメントが作成したページは、カーネルによってcopy-on-writeマークがつけられます。つまり、あるプロセスが__DATAセグメントのページに書き込みすると、そのプロセス専用のコピーが渡されるのです。

__OBJC

__OBJCセグメントは、Objective-Cで使用されるライブラリのデータを含みます。

__IMPORT

__IMPORTセグメントは、シンボルスタブと実行ファイルで定義されていないシンボルへのnon-lazyポインタを含みます。このセグメントは、IA-32アーキテクチャの実行ファイルにのみ生成されます。

__LINKEDIT

__LINKEDITセグメントは、シンボル、文字列、再配置テーブルなどの、ダイナミックリンカが使用するデータを含みます。