Linuxなどの実行ファイルやコンパイラから出力されるオブジェクトファイルはELFという形式だが、 macOSではMach-Oという別のフォーマットが使われている。 このフォーマットを学んでみる、 要するにELFのオブジェクトファイル形式を生成するをMach-O/aarch64上でやってみる。
環境:Apple M1, macOS Sonoma 14.5, Apple clang version 15.0.0 (clang-1500.3.9.4)
Mach-Oの構成
Mach-Oフォーマットのファイルは、ヘッダとロードコマンド(複数)、他は任意という構成になっている。 コマンドにはいろいろな種類があり、オブジェクトファイルに重要な項目としてセグメントとセクション、シンボルテーブル、文字列テーブル、再配置情報がある。
Mach-Oファイル内容の確認方法
どのような内容のファイルを生成したらいいのか調べるために、gccなどの既存のコンパイラから出力したものの内容を確認する方法。 otoolやdsymutilやobjdumpを使うとよい。
題材としてaarch64用の以下のアセンブリコードを使用する:
.text |
$ gcc -c hello.s # hello.oが出力される |
machヘッダ
machヘッダはファイルの先頭32バイトで、内容はstruct mach_header_64
:
struct mach_header_64 { |
となる。オブジェクトファイルをダンプしてみると、
$ xxd hello.o | head -n2 |
ヘッダ内容を表示するにはotool -hv
を使う:
$ otool -hv hello.o |
ロードコマンド
machヘッダ内のncmds
に従ってロードコマンドという情報が続く。
ロードコマンドはstruct load_command
:
struct load_command { |
となっていて、コマンド番号に従ってデータが格納される。
コマンド内容によってサイズはまちまちになるが、cmdsize
進めることで次のロードコマンドを辿ることができる。
ロードコマンドを表示するにはotool -lv
:
$ otool -lv hello.o |
セクション
ロードコマンドのセグメントコマンド内(上記のLC_SEGMENT_64
)にセクション情報が含まれている。
セクションのみを一覧で見るにはobjdump --section-headers
:
$ objdump --section-headers hello.o |
シンボルテーブル
dsymutil -s
:
$ dsymutil -s hello.o |
またはobjdump --syms
:
$ objdump --syms hello.o |
- シンボルにはどのセクションかの情報が含まれる
- セクション番号は1オリジン
- ただし
n_value
はセクション先頭ではなくセグメント先頭から何バイト目かという風に指定される? (セクション2のaddr
は0x24
だが、msg
のn_value
も0x24
となっている)
- シンボル名は文字列テーブルのバイト位置を指すことで指定
- 外部公開シンボルは
EXT
(そうでなければローカル) - 外部参照(
_write
)はUNDF
でセクション0となる
再配置情報
otool -rv
:
$ otool -rv hello.o |
またはobjdump --reloc
:
$ objdump --reloc hello.o |
- 再配置情報はセグメントに対応していて、そのセグメント内のオフセットと、再配置のタイプと計算に使用するシンボルが含まれる
_write
呼び出しはbl
1命令なので、再配置情報は1つmsg
参照は2命令に分かれているので、再配置情報も2つ
オブジェクトファイルでHello world
Mach-Oオブジェクトファイルを自分で生成してみる:
|
- 必要なロードコマンドはセグメント、ビルドバージョン、シンボルテーブルの3つ
- ビルドバージョンを含めないとリンクに失敗する
- セグメントコマンドに続いてセクション情報を列挙し、コマンドサイズにも含める
~off
というフィールドがファイル内のどこに配置されているかを示す- 8バイト程度でアライメントする必要があるかもしれない
実行する:
$ gcc -o hello_obj hello_obj.c |
出力されたmyhello.o の中身:
# machヘッダ (struct mach_header_64) |
リンク
- aidansteele/osx-abi-macho-file-format-reference: Mirror of OS X ABI Mach-O File Format Reference
- Mach-Oの構造メモ - blog
- Mach-Oのセグメント&セクション定義を読み込む - teru_kusu’s diary
- Mach-Oのシンボルテーブルを読み込む - teru_kusu’s diary
続編:Mach-Oを力任せに解析&再現、Macの実行ファイルを自作しちゃる!