url: https://dminor11th.blogspot.com/2011/07/mach-o.html
title: "Mach-Oファイル形式と、それにまつわるツール"
description: "「Mach-O」とは Mac OS X におけるオブジェクトファイルのフォーマットのこと(LinuxにおけるELFみたいなもの)。詳しいことは apple.com のドキュメント「 Mac OS X ABI Mach-O File Format Reference 」にとても分か..."
host: dminor11th.blogspot.com
favicon: https://dminor11th.blogspot.com/favicon.ico
url: https://zenn.dev/edom18/articles/mach-o-format
title: "Mach-O フォーマットを調べがてら otool 風出力をしてみる"
host: zenn.dev
image: https://res.cloudinary.com/zenn/image/upload/s--l142Pxvu--/c_fit%2Cg_north_west%2Cl_text:notosansjp-medium.otf_55:Mach-O%2520%25E3%2583%2595%25E3%2582%25A9%25E3%2583%25BC%25E3%2583%259E%25E3%2583%2583%25E3%2583%2588%25E3%2582%2592%25E8%25AA%25BF%25E3%2581%25B9%25E3%2581%258C%25E3%2581%25A6%25E3%2582%2589%2520otool%2520%25E9%25A2%25A8%25E5%2587%25BA%25E5%258A%259B%25E3%2582%2592%25E3%2581%2597%25E3%2581%25A6%25E3%2581%25BF%25E3%2582%258B%2Cw_1010%2Cx_90%2Cy_100/g_south_west%2Cl_text:notosansjp-medium.otf_37:Kazuya%2520Hiruma%2Cx_203%2Cy_121/g_south_west%2Ch_90%2Cl_fetch:aHR0cHM6Ly9zdG9yYWdlLmdvb2dsZWFwaXMuY29tL3plbm4tdXNlci11cGxvYWQvYXZhdGFyL2YxNTFjMzAzY2MuanBlZw==%2Cr_max%2Cw_90%2Cx_87%2Cy_95/v1627283836/default/og-base-w1200-v2.png
Mach-O とは?
url: https://ja.wikipedia.org/wiki/Mach-O
title: "Mach-O - Wikipedia"
host: ja.wikipedia.org
favicon: https://ja.wikipedia.org/static/favicon/wikipedia.ico
Mach-O は オブジェクトファイルや実行ファイルのフォーマットの 1 つです。 #OSX においてはこれが標準のバイナリファイルフォーマットになっています。
Mach-O プログラムを調べるには otool というコマンドを使うとよいです。 これは Linux における readelf です。
OTOOL-CLASSIC(1) General Commands Manual OTOOL-CLASSIC(1)
NAME
otool-classic - object file displaying tool
SYNOPSIS
otool-classic [ option ... ] [ file ... ]
DESCRIPTION
The otool-classic command displays specified parts of object files or libraries. It is the preferred tool for inspecting Mach-O binaries, especially for binaries that are bad, corrupted, or fuzzed. It is also useful in situations
when inspecting files with new or "bleeding-edge" Mach-O file format changes.
otool で実行ファイルを調べてみる
header
-h で Mach-O ファイルのヘッダを表示します。 CPU の種類や EXECUTE 実行可能タイプである、などが記されています。
playground/c-compile-assemble on feature/learn-c-compile-assemble via C v17.0.0-clang [☁️ ]
❯ otool -hv a.out
a.out:
Mach header
magic cputype cpusubtype caps filetype ncmds sizeofcmds flags
MH_MAGIC_64 ARM64 ALL 0x00 EXECUTE 18 1208 NOUNDEFS DYLDLINK TWOLEVEL PIE
Mach-O において最初にきます。
text
-t で .text
つまり主記憶装置メモリにロードされる命令領域を表示できます。
main, doubled, add というラベル (関数) が存在し、それらのアセンブリコードが機械語で書かれていることがわかります。
playground/c-compile-assemble on feature/learn-c-compile-assemble via C v17.0.0-clang [☁️ ]
❯ otool -tv a.out
a.out:
(__TEXT,__text) section
_main:
00000001000004f8 sub sp, sp, #0x30
00000001000004fc stp x29, x30, [sp, #0x20]
0000000100000500 add x29, sp, #0x20
0000000100000504 mov w8, #0x0
0000000100000508 str w8, [sp, #0x8]
000000010000050c stur wzr, [x29, #-0x4]
0000000100000510 stur w0, [x29, #-0x8]
0000000100000514 str x1, [sp, #0x10]
0000000100000518 mov w0, #0x5
000000010000051c mov w1, #0x8
0000000100000520 bl _add
0000000100000524 str w0, [sp, #0xc]
0000000100000528 ldr w8, [sp, #0xc]
000000010000052c mov x9, sp
0000000100000530 str x8, [x9]
0000000100000534 adrp x0, 0 ; 0x100000000
0000000100000538 add x0, x0, #0x5bc ; literal pool for: "Sum = %d\n"
000000010000053c bl 0x1000005b0 ; symbol stub for: _printf
0000000100000540 ldr w0, [sp, #0x8]
0000000100000544 ldp x29, x30, [sp, #0x20]
0000000100000548 add sp, sp, #0x30
000000010000054c ret
_doubled:
0000000100000550 sub sp, sp, #0x10
0000000100000554 str w0, [sp, #0xc]
0000000100000558 ldr w8, [sp, #0xc]
000000010000055c lsl w0, w8, #1
0000000100000560 add sp, sp, #0x10
0000000100000564 ret
_add:
0000000100000568 sub sp, sp, #0x20
000000010000056c stp x29, x30, [sp, #0x10]
0000000100000570 add x29, sp, #0x10
0000000100000574 stur w0, [x29, #-0x4]
0000000100000578 str w1, [sp, #0x8]
000000010000057c adrp x8, 8 ; 0x100008000
0000000100000580 add x8, x8, #0x0
0000000100000584 ldr w8, [x8]
0000000100000588 str w8, [sp, #0x4]
000000010000058c ldur w0, [x29, #-0x4]
0000000100000590 bl _doubled
0000000100000594 ldr w8, [sp, #0x4]
0000000100000598 add w8, w8, w0
000000010000059c ldr w9, [sp, #0x8]
00000001000005a0 add w0, w8, w9
00000001000005a4 ldp x29, x30, [sp, #0x10]
00000001000005a8 add sp, sp, #0x20
00000001000005ac ret
reverse-assemblel せずにそのままバイトデータを表示するときは下記のように -t だけつけます。
d100c3ff = sub sp, sp, #0x30
であり、objdump を使ってみる の逆アセンブルでも同様の結果が得られています。
命令は 4 byte 単位の chunk で表され、たとえば d100c3ff = 4byte で 1 命令 (sub sp, sp, 0x30 という opcode + operand) です。
00000001000004f8 ~ 4fb
に d100c3ff00000001000004fc ~ 4ff
に a9027bfd- …
と命令が格納されています。
playground/c-compile-assemble on feature/learn-c-compile-assemble via C v17.0.0-clang [☁️ ]
❯ otool -t a.out
a.out:
(__TEXT,__text) section
00000001000004f8 d100c3ff a9027bfd 910083fd 52800008
0000000100000508 b9000be8 b81fc3bf b81f83a0 f9000be1
0000000100000518 528000a0 52800101 94000012 b9000fe0
0000000100000528 b9400fe8 910003e9 f9000128 90000000
0000000100000538 9116f000 9400001d b9400be0 a9427bfd
0000000100000548 9100c3ff d65f03c0 d10043ff b9000fe0
0000000100000558 b9400fe8 531f7900 910043ff d65f03c0
0000000100000568 d10083ff a9017bfd 910043fd b81fc3a0
0000000100000578 b9000be1 90000048 91000108 b9400108
0000000100000588 b90007e8 b85fc3a0 97fffff0 b94007e8
0000000100000598 0b000108 b9400be9 0b090100 a9417bfd
00000001000005a8 910083ff d65f03c0
load command
url: https://zenn.dev/edom18/articles/mach-o-format#%E3%83%AD%E3%83%BC%E3%83%89%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89
title: "Mach-O フォーマットを調べがてら otool 風出力をしてみる"
host: zenn.dev
image: https://res.cloudinary.com/zenn/image/upload/s--l142Pxvu--/c_fit%2Cg_north_west%2Cl_text:notosansjp-medium.otf_55:Mach-O%2520%25E3%2583%2595%25E3%2582%25A9%25E3%2583%25BC%25E3%2583%259E%25E3%2583%2583%25E3%2583%2588%25E3%2582%2592%25E8%25AA%25BF%25E3%2581%25B9%25E3%2581%258C%25E3%2581%25A6%25E3%2582%2589%2520otool%2520%25E9%25A2%25A8%25E5%2587%25BA%25E5%258A%259B%25E3%2582%2592%25E3%2581%2597%25E3%2581%25A6%25E3%2581%25BF%25E3%2582%258B%2Cw_1010%2Cx_90%2Cy_100/g_south_west%2Cl_text:notosansjp-medium.otf_37:Kazuya%2520Hiruma%2Cx_203%2Cy_121/g_south_west%2Ch_90%2Cl_fetch:aHR0cHM6Ly9zdG9yYWdlLmdvb2dsZWFwaXMuY29tL3plbm4tdXNlci11cGxvYWQvYXZhdGFyL2YxNTFjMzAzY2MuanBlZw==%2Cr_max%2Cw_90%2Cx_87%2Cy_95/v1627283836/default/og-base-w1200-v2.png
ヘッダに続いて配置されるデータがロードコマンドです。 OSX のローダーに対する命令であり、プログラムをメモリにロードするために必要な情報を OS に伝えます。
ロードコマンドをみることで、 OSX の Mach-O 実行ファイルのプログラムがどう主記憶装置メモリの番地に展開・ロードされるのかがわかります。
vmaddr = 仮想アドレスの 0x0000000000000000 に 0x0000000100000000 のサイズのロードコマンド 0 が配置される、ということがわかります。
❮ otool -l a.out
a.out:
Load command 0
cmd LC_SEGMENT_64
cmdsize 72
segname __PAGEZERO
vmaddr 0x0000000000000000
vmsize 0x0000000100000000
fileoff 0
filesize 0
maxprot 0x00000000
initprot 0x00000000
nsects 0
flags 0x0
また、 .text
を詳しくみたときにでてきた 0x00000001000004f8 が再びでてきています。
これは 0x00000001000004f8 仮想アドレス番地から 0x00000000000000b8 のサイズだけ命令が配置される、ということがわかります。
Section
sectname __text
segname __TEXT
addr 0x00000001000004f8
size 0x00000000000000b8
offset 1272
align 2^2 (4)
reloff 0
nreloc 0
flags 0x80000400
reserved1 0
reserved2 0
.data
の仮想アドレス上の配置場所もわかります。
Section
sectname __data
segname __DATA
addr 0x0000000100008000
size 0x0000000000000004
offset 32768
align 2^2 (4)
reloff 0
nreloc 0
flags 0x00000000
reserved1 0
reserved2 0
stack-frame やヒープの領域はロードコマンドからはわかりません。 実行時に動的に割り当てられるため、 gdb lldb でメモリマップを調べます。
data
-d でデータ領域を確認できます。 0000000100008000 に globalW の値 0x64 = 100 が格納されていることがわかります。
❯ otool -dv a.out
a.out:
(__DATA,__data) section
0000000100008000 00000064