Mach-O入門

Mach-O(Mach object)

Mach-OとはMach objectの略で、Mac OS Xでプログラムやライブラリをディスクに格納する際に使用されるファイルフォーマットです。Mach-Oのファイルは、先頭にヘッダがあり、load commandおよびsegmentがその後にあります。segmentは複数のsectionを含んでいて、1から連番が振られています。

http://developer.apple.com/documentation/DeveloperTools/Conceptual/MachORuntime/art/mach_o_segments.gif

これらのヘッダの構造は、mach-o/loader.hに記述されています。

Mach-Oヘッダ

Mach-Oファイルは1つのアーキテクチャ向けのコードとデータを格納しています。どのアーキテクチャ向けのファイルかは、Mach-Oヘッダに格納されています。複数のアーキテクチャ向けのMach-Oファイルをまとめたものが、いわゆるユニバーサルバイナリと呼ばれるものです。
Mach-OヘッダはすべてのMach-Oファイルの先頭に必ず存在し、そのファイルがMach-Oファイルであることを表します。Mach-Oヘッダの内容は、otool(1)の-hオプションで見ることができます。

> otool -h /sw/bin/zsh 
/sw/bin/zsh:
Mach header
      magic cputype cpusubtype   filetype ncmds sizeofcmds      flags
 0xfeedface       7          3          2    15       1588 0x00002085

-vオプションを使用すると、多少親切な表示になります。

> otool -h -v /sw/bin/zsh
/sw/bin/zsh:
Mach header
      magic cputype cpusubtype   filetype ncmds sizeofcmds      flags
   MH_MAGIC    I386        ALL    EXECUTE    15       1588   NOUNDEFS DYLDLINK TWOLEVEL SUBSECTIONS_VIA_SYMBOLS

Mach-Oヘッダは次のような構造をしています。

struct mach_header {
	uint32_t	magic;		/* マジックナンバー */
	cpu_type_t	cputype;	/* CPUタイプ */
	cpu_subtype_t	cpusubtype;	/* CPUサブタイプ */
	uint32_t	filetype;	/* ファイル形式 */
	uint32_t	ncmds;		/* load commandの数 */
	uint32_t	sizeofcmds;	/* load commandのサイズ */
	uint32_t	flags;		/* フラグ */
};

magicはマジックナンバーです。32bitのMach-Oファイルでは0xfeedface、64ビットのMach-Oファイルでは0xfeedfacfです。
cputypeおよびcpusubtypeはmach/machine.hで記述されているCPU種別です。
filetypeは以下のどれかを表しています。

型名 説明
MH_OBJECT 0x1 再配置可能なオブジェクトファイル
MH_EXECUTE 0x2 実行可能ファイル
MH_CORE 0x4 コアファイル
MH_DYLIB 0x6 共有ライブラリ
MH_DYLINKER 0x7 ダイナミックリンカ共有ライブラリ
MH_BUNDLE 0x8 バンドルファイル

ncmdsはload commandの数を表します。
sizeofcmdsはload commandの合計サイズを表します。
flagsはフラグです。以下のフラグがあります。

フラグ名 説明
MH_NOUNDEFS ビルド時に未解決の参照がないことを表します
MH_INCRLINK インクリメンタルリンクされていることを表します
MH_DYLDLINK ダイナミックリンクされていることを表します
MH_TWOLEVEL 2レベルの名前空間を使用していることを表します
MH_BINDATLOAD ロード時に未解決の参照を解決すべきことを表します
MH_PREBOUND 未解決の参照がprebindされていることを表します
MH_PREBINDABLE prebind可能であることを表します
MH_NOFIXPREBINDING prebind agentに通知しないことを表します
MH_ALLMODSBOUND 依存しているライブラリに対して2レベルの名前空間を使用してprebindされていることを表します
MH_CANONICAL prebindが解除されていることを表します
MH_SPLIT_SEGS 読み込み専用と読み書き可能なsegmentに分割されていることを表します
MH_FORCE_FLAT フラットな名前空間を使用していることを表します
MH_SUBSECTIONS_VIA_SYMBOLS sectionが分割可能であることを表します