第12回 Universal Binary【前編】Undocumented Mac OS X(3/5 ページ)

» 2007年11月30日 00時20分 公開
[白山貴之,ITmedia]

Mach-OとUniversal Binaryの詳細

 では、Universal Binaryがどういった実装なのかを見てみよう。

 まず、Mac OS XのバイナリフォーマットはほかのUNIXで一般的なELFやCOFFではなく、Mach-Oという形式である。Mach-Oの構造を簡単に説明すると図2のようになる。先頭にMachヘッダがあり、続いて可変長のLoad Commandsがあり、最後に実際のコードやデータをつなぎ合わせたデータ領域がある。Machヘッダには、Machヘッダであることを示す32ビットのmagicナンバー*「0xfeedface」と、対応するCPUのアーキテクチャを示す数値が記載されている(図3)

図2 図2 Mach-Oバイナリの構造
図3 図3 Machヘッダはこのような構造体で表現されている(/usr/include/mach-o/loader.h参照)。構造体の先頭のmagicには、それぞれMH_MAGICで表現される定数が書き込まれている。MH_CIGAMはエンディアンの異なる環境での比較用に定義されている。あらかじめ逆の値を用意しておくことで、エンディアンの変換を1回省略できるからだ

 Load Commandsはダイナミックローダー(dyld)によって実行されるコマンドの集まりで、コードを格納するTEXTセグメントやDATAセグメント、スタックといったメモリ領域を確保、確保したメモリ領域に対して実行ファイルの一部をマップしたり、レジスタの値を設定したり、スレッドを呼び起こしTEXTセグメントにマップされたコードを実行するといった処理が記載されている(図4)。実行ファイルのデータ領域は特に構造を持たないが、このLoad Commandsを読み解いていくことで複数のバイナリデータをつなぎ合わせたものであると分かる。

図4 図4 Load commadsの構造。Load commandsはMachヘッダの後ろに配置され、共通のload_command構造体とそれぞれのコマンドに特有の構造体の組み合わせで構成されている
図5

 Universal Binaryでは、このMachヘッダの前にFATヘッダとfat_archという構造体が置かれる(図5)。FATヘッダにはそれを表すmagicナンバー「0xcafebabe」が記載され、続けてその後に幾つfat_arch構造体が続いているかが示されている。fat_arch構造体にはCPUのアーキテクチャを示す数値とそのアーキテクチャに対応するMachヘッダへのオフセットが記録されている(図6、コラム3

図5 Universal Binaryの構造。Universal Binaryでは、MachヘッダではなくFATヘッダがファイルの先頭に存在する。FATヘッダの後にはfat_arch構造体があり、それぞれの後ろに続くMachヘッダのオフセットを記録している(編集部注:図5はデザイン上の都合でアイコンとして用意しました。上記アイコンをクリックいただくことでご覧いただけます)
図6 図6 FATヘッダとfat_arch構造体。Universal Binaryでは、MachヘッダではなくFATヘッダが先頭に配置される。FATヘッダには定数FAT_MAGICと、続くfat_archの数が記録されている。fat_arch構造体はFATヘッダの後にnfat_archで指定された数だけ配置される。それぞれ、Universal Binaryに含まれるコードに対応し、どのアーキテクチャに対応するか、そのファイル内でのオフセットはどこかなどが記録される

 Darwinカーネルのexecシステムコールは、実行するファイルの先頭が「0xfeedface」だったらそのままdyldに制御を移すが、「0xcafebabe」の場合はこのfat_arch構造体を順番に読み、自身のアーキテクチャに最も適合するものを選択、Machヘッダを読み込みdyldに制御を移す(実行例1、2)


% od -x /bin/ls | less
0000000 feed face 0000 0012 0000 0000 0000 0002
0000020 0000 000b 0000 0648 0000 0085 0000 0001
0000040 0000 0038 5f5f 5041 4745 5a45 524f 0000

実行例1 非Universal Binaryのダンプ。ファイルの先頭にMach-Oのmagicナンバーである0xfeedfaceがあるのが分かる

% od -x a.out | less
0000000 cafe babe 0000 0002 0000 0012 0000 0000
0000020 0000 1000 0000 4554 0000 000c 0000 0007
0000040 0000 0003 0000 6000 0000 39b0 0000 000c
0000060 0000 0000 0000 0000 0000 0000 0000 0000
*
0010000 feed face 0000 0012 0000 0000 0000 0002
0010020 0000 000a 0000 0544 0000 0085 0000 0001
0010040 0000 0038 5f5f 5041 4745 5a45 524f 0000

実行例2 Universal Binaryのダンプ。ファイルの先頭にFATヘッダのmagicナンバーである0xcafebabeがあるのが分かる

 なお、先頭16バイトが「0x2321」(ASCIIで「#!」)だった場合、一般のUNIXと同様に実行ファイルはスクリプトだと見なされる。「#!」に続けて指定されたインタープリタに制御が移り、スクリプトが実行される。

Intel CPU搭載Macの場合

 Intel CPUを搭載したMacのカーネルでは、若干処理が異なる。実行ファイルにx86のコードが含まれていない場合、今度はPowerPCのコードを探し、/usr/libexec/oahにあるtransitというバイナリを経由してこれを「実行」する。残念ながらこの部分に関してはまだソースが公開されてないため詳細は不明だが、このtransitというコマンドと、transitからMach-IPCを使って起動されるtransitedというサーバプロセスが、PowerPCコードをIntelのコードに変換するトランスレータ、Rosettaの実体であろう。

このページで出てきた専門用語

magicナンバー

プログラム中に表れる、明確な意味や役割を持つ具体的な値。


関連キーワード

Mac | Mac OS X | x86 | Apple | WWDC


Copyright © ITmedia, Inc. All Rights Reserved.

注目のテーマ