概要
「独習アセンブラ」を読んでアセンブラを学んでいて、apple silicon(arm)のmacのローカル環境でコード書いてデバッグしています。
4.5「デバッガによるトレース」 で、gdbを使ってcのソースコードをコンパイルした実行ファイルをもとにトレースを行いますが、arm版macでは書籍の内容の通りにトレースができませんでした。
arm版macではデバッグに使うgdbをインストールするのが面倒なので、本とは違う方法でデバッグする方法を模索し、lldbというデバッガを使ってうまいことできそうだったのでその手順をまとめます。
低レイヤーに関する理解が曖昧で、独学で学習を進めながらまとめている状態で、所々用語が間違っているかもですがご容赦ください。
前提
- OS: macOS Monterey 12.5
- Chip: Apple M1(Arm)
- lldb: lldb-1316.0.9.46 Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)
- gcc,clang: Apple clang version 13.1.6 (clang-1316.0.21.2.5) Target: arm64-apple-darwin21.6.0 Thread model: posix
手順
lldbの確認
lldbは元々インストールされていたのですが、念のため使えることを確認します。
which lldb /usr/bin/lldb lldb --version lldb-1316.0.9.46 Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12) # lldbも実行できることを確認 lldb (lldb)
テスト用のCプログラムを作成する
「独習アセンブラ」のサポートページに記載されている、サンプルコードの通りに作成します。
ここでは、add.c
という名前で保存します。
/** * 4.5.1 Cからアセンブリ言語への変換確認用 */ int main(void) { register int i, j; i = 123; i = i + 1; j = 456; j = i + j; return j; }
add.cのコンパイル
本に記載されている通りにgccでコンパイルする場合、問題なく実行ファイルadd
を生成できますが、lldbでのブレークポイントのセットの時にno locations (pending)
というエラーが出てしまいます。
# コンパイルしてaddに実行ファイルを出力 gcc -fno-pic -fomit-frame-pointer -o add add.c; # lldbによるデバッグ実行 # ここでは試しにadd.cの12行目にブレークポイントを貼ります。 (lldb) breakpoint set --file add.c --line 12 Breakpoint 1: no locations (pending). WARNING: Unable to resolve breakpoint to any actual locations.
gccでは -gを指定して、デバッグ可能な状態でコンパイルする必要があり、上記のgccコマンドに-gを追加することで問題なくブレークポイントをセットできました。
gcc --help ... -g Generate source-level debug information
# -gを追加してデバッグを有効にしたうえでコンパイル gcc -g -fno-pic -fomit-frame-pointer -o add add.c; # lldbを実行し、ブレークポイントを12, 13, 14行目に貼る。 lldb add (lldb) target create "add" Current executable set to '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64). (lldb) breakpoint set --file add.c --line 12 Breakpoint 1: where = add`main + 40 at add.c:12:9, address = 0x0000000100003f30 (lldb) breakpoint set --file add.c --line 13 Breakpoint 2: where = add`main + 56 at add.c:13:23, address = 0x0000000100003f40 (lldb) breakpoint set --file add.c --line 14 Breakpoint 3: where = add`main + 84 at add.c:14:12, address = 0x0000000100003f5c (lldb) r Process 26586 launched: '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64) Process 26586 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100003f30 add`main at add.c:12:9 9 i = 123; 10 i = i + 1; 11 j = 456; -> 12 j = i + j; 13 printf("j: %d\n", j); 14 return j; 15 } Target 0: (add) stopped.
補足
上記のブレークポイントに関するエラーについて色々調べたところ、gccでなくclangでも同じ感じでコンパイルできます。
github.com
clang -g -O0 add.c -o add -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer
gccの方では -fomit-frame-pointer
をつけていましたが、clangでもgccの-fomit-frame-pointer
と同じ設定をするには、
-fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer
の両方を指定する必要があるとのことだったのでそのまま指定しています。
The problem ended up being that, on x86-64 Linux at least, Clang requires both -fno-omit-frame-pointer and -mno-omit-leaf-frame-pointer in order to get the same behavior that gcc gives with only -fno-omit-frame-pointer. See this LLVM bug: "Need both -fno-omit-frame-pointer and -mno-omit-leaf-frame-pointer to get a fp on linux on a leaf function"
これで一通り下記のことができるようになりました。 - lldbによるデバッグができる状態でコンパイルする - lldbで実行ファイルに対してブレークポイントを貼る
lldbによるデバッグ
前項でかるく説明しましたが、lldbによるデバッグを実行します。
ここではcのソースコードの所定の行にブレークポイントを貼り、デバッグモードで実行し、それぞれのブレークポイントで下記の内容を確認します。
- 実行ファイルから逆アセンブルし、アセンブリコードレベルでのデバッグ
- レジスターの内容の確認
前述でやったのと同じ感じで、lldbを起動し、ブレークポイントを張っていきます。
# lldbを実行し、ブレークポイントを12, 13, 14行目に貼る。 lldb add (lldb) target create "add" Current executable set to '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64). (lldb) breakpoint set --file add.c --line 12 Breakpoint 1: where = add`main + 40 at add.c:12:9, address = 0x0000000100003f30 (lldb) breakpoint set --file add.c --line 13 Breakpoint 2: where = add`main + 56 at add.c:13:23, address = 0x0000000100003f40 (lldb) breakpoint set --file add.c --line 14 Breakpoint 3: where = add`main + 84 at add.c:14:12, address = 0x0000000100003f5c (lldb) r Process 26586 launched: '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64) Process 26586 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 frame #0: 0x0000000100003f30 add`main at add.c:12:9 9 i = 123; 10 i = i + 1; 11 j = 456; -> 12 j = i + j; 13 printf("j: %d\n", j); 14 return j; 15 } Target 0: (add) stopped.
ブレークポイントを貼る
下記のように、breakpoint set を使って、ソースコードのファイルと行数を指定してブレークポイントを貼ることができます。
breakpoint set --file add.c --line 12
breakpoinは、エイリアスとしてb
でも使えます。
使い方は、help b
で見ることができ、上記と同じ内容でもっと簡潔に書くことができます。
breakpoint -- Commands for operating on breakpoints (see 'help b' for shorthand.)
(lldb) help b Set a breakpoint using one of several shorthand formats. Expects 'raw' input (see 'help raw-input'.) Syntax: _regexp-break <filename>:<linenum>:<colnum> main.c:12:21 // Break at line 12 and column 21 of main.c
下記のように簡単に書けます。
(lldb) b add.c:12 Breakpoint 7: where = add`main + 40 at add.c:12:9, address = 0x0000000100003f30 (lldb) b add.c:13 Breakpoint 8: where = add`main + 56 at add.c:13:23, address = 0x0000000100003f40 (lldb) b add.c:14 Breakpoint 9: where = add`main + 84 at add.c:14:12, address = 0x0000000100003f5c
デバッグの実行
ここで、ブレークポイントを設定したので、デバッグの実行をしていきます。
r
を使ってデバッグ実行を開始できます。
r -- Launch the executable in the debugger.
ブレークポイントを貼った状態で実行します。
# ブレークポイント ... (lldb) b add.c:14 Breakpoint 11: where = add`main + 84 at add.c:14:12, address = 0x0000000100003f5c # デバッグ実行 (lldb) r There is a running process, kill it and restart?: [Y/n] y Process 27285 exited with status = 9 (0x00000009) Process 27388 launched: '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64) Process 27388 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 4.1 7.1 frame #0: 0x0000000100003f30 add`main at add.c:12:9 9 i = 123; 10 i = i + 1; 11 j = 456; -> 12 j = i + j; 13 printf("j: %d\n", j); 14 return j; 15 } Target 0: (add) stopped. (lldb)
12, 13 ,14行目に貼っているので、最初のブレークポイントで止まっている状態です。
レジスターの状態の確認
この状態で、register read
を実行することで、ブレークポイントで止まっている位置でのレジスタの状態を確認できます。
ここでは先ほどと重複しますが、 12行目でのレジスタの状態を確認しています。
11行目で j = 456
となっていますが、x8のレジスタにjにセットされている456(16進数で1C8)の値があることが確認できます。
(lldb) r There is a running process, kill it and restart?: [Y/n] y Process 27285 exited with status = 9 (0x00000009) Process 27388 launched: '/Users/hoge/Documents/code/assembly-language-training/src/tr-regs/add' (arm64) Process 27388 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 4.1 7.1 frame #0: 0x0000000100003f30 add`main at add.c:12:9 9 i = 123; 10 i = i + 1; 11 j = 456; -> 12 j = i + j; 13 printf("j: %d\n", j); 14 return j; 15 } Target 0: (add) stopped. (lldb) register read General Purpose Registers: x0 = 0x0000000000000001 x1 = 0x000000016fdff538 x2 = 0x000000016fdff548 x3 = 0x000000016fdff6b0 x4 = 0x0000000000000000 x5 = 0x0000000000000000 x6 = 0x0000000000000000 x7 = 0x0000000000000000 x8 = 0x00000000000001c8 # <- ここで456の値がセットされている。 x9 = 0x0000000000000002 x10 = 0x0000000000000000 x11 = 0x0000000000000002 x12 = 0x0000000000000002 x13 = 0x0000000000000000 x14 = 0x0000000000000008 x15 = 0x0000000000000000 x16 = 0x0000000300033088 x17 = 0x6ae100016fdfe7d0 x18 = 0x0000000000000000 x19 = 0x00000001000c0060 x20 = 0x0000000100003f08 add`main at add.c:7 x21 = 0x000000010006c070 dyld`dyld4::sConfigBuffer x22 = 0x0000000000000000 x23 = 0x0000000000000000 x24 = 0x0000000000000000 x25 = 0x0000000000000000 x26 = 0x0000000000000000 x27 = 0x0000000000000000 x28 = 0x0000000000000000 fp = 0x000000016fdff510 lr = 0x000000010001108c dyld`start + 520 sp = 0x000000016fdff3a0 pc = 0x0000000100003f30 add`main + 40 at add.c:12:9 cpsr = 0x60001000
実行中プログラムを逆アセンブルしたアセンブルコードを表示する
先ほどはcのソースファイルレベルでどこでブレークされているかを確認できましたが、この実行ファイルを逆アセンブリしたアセンブルコードレベルでどの状態にいるかを確認できます。
lldbのdi
コマンドで確認ができます。
di -- Disassemble specified instructions in the current target. Defaults to the current function for the current thread and stack frame.
ここでアセンブリコードを確認します。
(lldb) di add`main: 0x100003f08 <+0>: sub sp, sp, #0x30 0x100003f0c <+4>: stp x29, x30, [sp, #0x20] 0x100003f10 <+8>: str wzr, [sp, #0x1c] 0x100003f14 <+12>: mov w8, #0x7b 0x100003f18 <+16>: str w8, [sp, #0x18] 0x100003f1c <+20>: ldr w8, [sp, #0x18] 0x100003f20 <+24>: add w8, w8, #0x1 0x100003f24 <+28>: str w8, [sp, #0x18] 0x100003f28 <+32>: mov w8, #0x1c8 0x100003f2c <+36>: str w8, [sp, #0x14] -> 0x100003f30 <+40>: ldr w8, [sp, #0x18] 0x100003f34 <+44>: ldr w9, [sp, #0x14] 0x100003f38 <+48>: add w8, w8, w9 0x100003f3c <+52>: str w8, [sp, #0x14] 0x100003f40 <+56>: ldr w9, [sp, #0x14] 0x100003f44 <+60>: mov x8, x9 0x100003f48 <+64>: adrp x0, 0 0x100003f4c <+68>: add x0, x0, #0xf78 ; "j: %d\n" 0x100003f50 <+72>: mov x9, sp 0x100003f54 <+76>: str x8, [x9] 0x100003f58 <+80>: bl 0x100003f6c ; symbol stub for: printf 0x100003f5c <+84>: ldr w0, [sp, #0x14] 0x100003f60 <+88>: ldp x29, x30, [sp, #0x20] 0x100003f64 <+92>: add sp, sp, #0x30 0x100003f68 <+96>: ret (lldb)
lldb上では 左側に->
が表示されている行が、現在のプログラムの位置となります。
ソースコード上の位置と、アセンブリコードの位置を確認してみます。
cでは、 j = i + j
という処理をしているところとなります。
-> 12 j = i + j;
ここでは、ldrというオペコードで、w8, w9にそれぞれi と jの値を読み込み、add w8, w8, w9
で、w8とw9の値を足した結果をw8レジスタに格納することで j = i + j
の処理を表しています。
-> 0x100003f30 <+40>: ldr w8, [sp, #0x18] 0x100003f34 <+44>: ldr w9, [sp, #0x14] 0x100003f38 <+48>: add w8, w8, w9
メモとして、オペコードは下記のページで確認できます。 - ARM LDR - ARM ADD
ここで、ブレークポイントで止まった箇所で下記2つを確認できました。 - ブレークポイントでのレジスタの状態 - 実行ファイルを逆アセンブルし、アセンブリコードレベルでどの処理を実行しているかの確認
次のブレークポイントまで処理を進める。
ここからは、次のブレークポイントへ処理を進めていきます。
下記の2つの方法で処理を進めることができます。
1.next
, n
: ソースコードレベルで次のブレークポイントまで進める(Cのソースコードの行数ごとに進める)
2. nexti
, ni
: 実際のアセンブリコードレベルで次のブレークポイントまで進める
n -- Source level single step, stepping over calls. Defaults to current thread unless specified. next -- Source level single step, stepping over calls. Defaults to current thread unless specified. nexti -- Instruction level single step, stepping over calls. Defaults to current thread unless specified. ni -- Instruction level single step, stepping over calls. Defaults to current thread unless specified.
2では、前項で説明したように、1で設定したCのソースコードの各行ごとに、アセンブリコードでは複数の処理となる可能性があるため、アセンブリコードレベルで1つ1つ処理を進めていく形になります。
例: 前項でj = i + j
という行は、アセンブリコードレベルではldr, ldr, add
と3つのオペコードに分割されているため3ステップになること。
ここではアセンブリコードレベルで、どのように処理を進むかを確認したいため、12行目のj = i + j
が終わるところまでnexti
を実行して1つずつ処理を進めていきます。
(lldb) nexti Process 27388 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x0000000100003f34 add`main at add.c:12:13 9 i = 123; 10 i = i + 1; 11 j = 456; -> 12 j = i + j; 13 printf("j: %d\n", j); 14 return j; 15 } Target 0: (add) stopped. (lldb) di add`main: 0x100003f08 <+0>: sub sp, sp, #0x30 0x100003f0c <+4>: stp x29, x30, [sp, #0x20] 0x100003f10 <+8>: str wzr, [sp, #0x1c] 0x100003f14 <+12>: mov w8, #0x7b 0x100003f18 <+16>: str w8, [sp, #0x18] 0x100003f1c <+20>: ldr w8, [sp, #0x18] 0x100003f20 <+24>: add w8, w8, #0x1 0x100003f24 <+28>: str w8, [sp, #0x18] 0x100003f28 <+32>: mov w8, #0x1c8 0x100003f2c <+36>: str w8, [sp, #0x14] 0x100003f30 <+40>: ldr w8, [sp, #0x18] -> 0x100003f34 <+44>: ldr w9, [sp, #0x14] 0x100003f38 <+48>: add w8, w8, w9 0x100003f3c <+52>: str w8, [sp, #0x14] 0x100003f40 <+56>: ldr w9, [sp, #0x14] 0x100003f44 <+60>: mov x8, x9 0x100003f48 <+64>: adrp x0, 0 0x100003f4c <+68>: add x0, x0, #0xf78 ; "j: %d\n" 0x100003f50 <+72>: mov x9, sp 0x100003f54 <+76>: str x8, [x9] 0x100003f58 <+80>: bl 0x100003f6c ; symbol stub for: printf 0x100003f5c <+84>: ldr w0, [sp, #0x14] 0x100003f60 <+88>: ldp x29, x30, [sp, #0x20] 0x100003f64 <+92>: add sp, sp, #0x30 0x100003f68 <+96>: ret (lldb) register read General Purpose Registers: x0 = 0x0000000000000001 x1 = 0x000000016fdff538 x2 = 0x000000016fdff548 x3 = 0x000000016fdff6b0 x4 = 0x0000000000000000 x5 = 0x0000000000000000 x6 = 0x0000000000000000 x7 = 0x0000000000000000 x8 = 0x000000000000007c x9 = 0x0000000000000002 x10 = 0x0000000000000000 x11 = 0x0000000000000002 x12 = 0x0000000000000002 x13 = 0x0000000000000000 x14 = 0x0000000000000008 x15 = 0x0000000000000000 x16 = 0x0000000300033088 x17 = 0x6ae100016fdfe7d0 x18 = 0x0000000000000000 x19 = 0x00000001000c0060 x20 = 0x0000000100003f08 add`main at add.c:7 x21 = 0x000000010006c070 dyld`dyld4::sConfigBuffer x22 = 0x0000000000000000 x23 = 0x0000000000000000 x24 = 0x0000000000000000 x25 = 0x0000000000000000 x26 = 0x0000000000000000 x27 = 0x0000000000000000 x28 = 0x0000000000000000 fp = 0x000000016fdff510 lr = 0x000000010001108c dyld`start + 520 sp = 0x000000016fdff3a0 pc = 0x0000000100003f34 add`main + 44 at add.c:12:13 cpsr = 0x60001000 (lldb) nexti Process 27388 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x0000000100003f38 add`main at add.c:12:11 9 i = 123; 10 i = i + 1; 11 j = 456; -> 12 j = i + j; 13 printf("j: %d\n", j); 14 return j; 15 } Target 0: (add) stopped. (lldb) di add`main: 0x100003f08 <+0>: sub sp, sp, #0x30 0x100003f0c <+4>: stp x29, x30, [sp, #0x20] 0x100003f10 <+8>: str wzr, [sp, #0x1c] 0x100003f14 <+12>: mov w8, #0x7b 0x100003f18 <+16>: str w8, [sp, #0x18] 0x100003f1c <+20>: ldr w8, [sp, #0x18] 0x100003f20 <+24>: add w8, w8, #0x1 0x100003f24 <+28>: str w8, [sp, #0x18] 0x100003f28 <+32>: mov w8, #0x1c8 0x100003f2c <+36>: str w8, [sp, #0x14] 0x100003f30 <+40>: ldr w8, [sp, #0x18] 0x100003f34 <+44>: ldr w9, [sp, #0x14] -> 0x100003f38 <+48>: add w8, w8, w9 0x100003f3c <+52>: str w8, [sp, #0x14] 0x100003f40 <+56>: ldr w9, [sp, #0x14] 0x100003f44 <+60>: mov x8, x9 0x100003f48 <+64>: adrp x0, 0 0x100003f4c <+68>: add x0, x0, #0xf78 ; "j: %d\n" 0x100003f50 <+72>: mov x9, sp 0x100003f54 <+76>: str x8, [x9] 0x100003f58 <+80>: bl 0x100003f6c ; symbol stub for: printf 0x100003f5c <+84>: ldr w0, [sp, #0x14] 0x100003f60 <+88>: ldp x29, x30, [sp, #0x20] 0x100003f64 <+92>: add sp, sp, #0x30 0x100003f68 <+96>: ret (lldb) register read General Purpose Registers: x0 = 0x0000000000000001 x1 = 0x000000016fdff538 x2 = 0x000000016fdff548 x3 = 0x000000016fdff6b0 x4 = 0x0000000000000000 x5 = 0x0000000000000000 x6 = 0x0000000000000000 x7 = 0x0000000000000000 x8 = 0x000000000000007c x9 = 0x00000000000001c8 x10 = 0x0000000000000000 x11 = 0x0000000000000002 x12 = 0x0000000000000002 x13 = 0x0000000000000000 x14 = 0x0000000000000008 x15 = 0x0000000000000000 x16 = 0x0000000300033088 x17 = 0x6ae100016fdfe7d0 x18 = 0x0000000000000000 x19 = 0x00000001000c0060 x20 = 0x0000000100003f08 add`main at add.c:7 x21 = 0x000000010006c070 dyld`dyld4::sConfigBuffer x22 = 0x0000000000000000 x23 = 0x0000000000000000 x24 = 0x0000000000000000 x25 = 0x0000000000000000 x26 = 0x0000000000000000 x27 = 0x0000000000000000 x28 = 0x0000000000000000 fp = 0x000000016fdff510 lr = 0x000000010001108c dyld`start + 520 sp = 0x000000016fdff3a0 pc = 0x0000000100003f38 add`main + 48 at add.c:12:11 cpsr = 0x60001000 (lldb) nexti Process 27388 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = instruction step over frame #0: 0x0000000100003f3c add`main at add.c:12:7 9 i = 123; 10 i = i + 1; 11 j = 456; -> 12 j = i + j; 13 printf("j: %d\n", j); 14 return j; 15 } Target 0: (add) stopped. (lldb) register read General Purpose Registers: x0 = 0x0000000000000001 x1 = 0x000000016fdff538 x2 = 0x000000016fdff548 x3 = 0x000000016fdff6b0 x4 = 0x0000000000000000 x5 = 0x0000000000000000 x6 = 0x0000000000000000 x7 = 0x0000000000000000 x8 = 0x0000000000000244 x9 = 0x00000000000001c8 x10 = 0x0000000000000000 x11 = 0x0000000000000002 x12 = 0x0000000000000002 x13 = 0x0000000000000000 x14 = 0x0000000000000008 x15 = 0x0000000000000000 x16 = 0x0000000300033088 x17 = 0x6ae100016fdfe7d0 x18 = 0x0000000000000000 x19 = 0x00000001000c0060 x20 = 0x0000000100003f08 add`main at add.c:7 x21 = 0x000000010006c070 dyld`dyld4::sConfigBuffer x22 = 0x0000000000000000 x23 = 0x0000000000000000 x24 = 0x0000000000000000 x25 = 0x0000000000000000 x26 = 0x0000000000000000 x27 = 0x0000000000000000 x28 = 0x0000000000000000 fp = 0x000000016fdff510 lr = 0x000000010001108c dyld`start + 520 sp = 0x000000016fdff3a0 pc = 0x0000000100003f3c add`main + 52 at add.c:12:7 cpsr = 0x60001000 (lldb) nexti Process 27388 stopped * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1 5.1 8.1 frame #0: 0x0000000100003f40 add`main at add.c:13:23 10 i = i + 1; 11 j = 456; 12 j = i + j; -> 13 printf("j: %d\n", j); 14 return j; 15 } Target 0: (add) stopped. (lldb) di add`main: 0x100003f08 <+0>: sub sp, sp, #0x30 0x100003f0c <+4>: stp x29, x30, [sp, #0x20] 0x100003f10 <+8>: str wzr, [sp, #0x1c] 0x100003f14 <+12>: mov w8, #0x7b 0x100003f18 <+16>: str w8, [sp, #0x18] 0x100003f1c <+20>: ldr w8, [sp, #0x18] 0x100003f20 <+24>: add w8, w8, #0x1 0x100003f24 <+28>: str w8, [sp, #0x18] 0x100003f28 <+32>: mov w8, #0x1c8 0x100003f2c <+36>: str w8, [sp, #0x14] 0x100003f30 <+40>: ldr w8, [sp, #0x18] 0x100003f34 <+44>: ldr w9, [sp, #0x14] 0x100003f38 <+48>: add w8, w8, w9 0x100003f3c <+52>: str w8, [sp, #0x14] -> 0x100003f40 <+56>: ldr w9, [sp, #0x14] 0x100003f44 <+60>: mov x8, x9 0x100003f48 <+64>: adrp x0, 0 0x100003f4c <+68>: add x0, x0, #0xf78 ; "j: %d\n" 0x100003f50 <+72>: mov x9, sp 0x100003f54 <+76>: str x8, [x9] 0x100003f58 <+80>: bl 0x100003f6c ; symbol stub for: printf 0x100003f5c <+84>: ldr w0, [sp, #0x14] 0x100003f60 <+88>: ldp x29, x30, [sp, #0x20] 0x100003f64 <+92>: add sp, sp, #0x30 0x100003f68 <+96>: ret (lldb) di add`main: 0x100003f08 <+0>: sub sp, sp, #0x30 0x100003f0c <+4>: stp x29, x30, [sp, #0x20] 0x100003f10 <+8>: str wzr, [sp, #0x1c] 0x100003f14 <+12>: mov w8, #0x7b 0x100003f18 <+16>: str w8, [sp, #0x18] 0x100003f1c <+20>: ldr w8, [sp, #0x18] 0x100003f20 <+24>: add w8, w8, #0x1 0x100003f24 <+28>: str w8, [sp, #0x18] 0x100003f28 <+32>: mov w8, #0x1c8 0x100003f2c <+36>: str w8, [sp, #0x14] 0x100003f30 <+40>: ldr w8, [sp, #0x18] 0x100003f34 <+44>: ldr w9, [sp, #0x14] 0x100003f38 <+48>: add w8, w8, w9 0x100003f3c <+52>: str w8, [sp, #0x14] -> 0x100003f40 <+56>: ldr w9, [sp, #0x14] 0x100003f44 <+60>: mov x8, x9 0x100003f48 <+64>: adrp x0, 0 0x100003f4c <+68>: add x0, x0, #0xf78 ; "j: %d\n" 0x100003f50 <+72>: mov x9, sp 0x100003f54 <+76>: str x8, [x9] 0x100003f58 <+80>: bl 0x100003f6c ; symbol stub for: printf 0x100003f5c <+84>: ldr w0, [sp, #0x14] 0x100003f60 <+88>: ldp x29, x30, [sp, #0x20] 0x100003f64 <+92>: add sp, sp, #0x30 0x100003f68 <+96>: ret (lldb) register read General Purpose Registers: x0 = 0x0000000000000001 x1 = 0x000000016fdff538 x2 = 0x000000016fdff548 x3 = 0x000000016fdff6b0 x4 = 0x0000000000000000 x5 = 0x0000000000000000 x6 = 0x0000000000000000 x7 = 0x0000000000000000 x8 = 0x0000000000000244 x9 = 0x00000000000001c8 x10 = 0x0000000000000000 x11 = 0x0000000000000002 x12 = 0x0000000000000002 x13 = 0x0000000000000000 x14 = 0x0000000000000008 x15 = 0x0000000000000000 x16 = 0x0000000300033088 x17 = 0x6ae100016fdfe7d0 x18 = 0x0000000000000000 x19 = 0x00000001000c0060 x20 = 0x0000000100003f08 add`main at add.c:7 x21 = 0x000000010006c070 dyld`dyld4::sConfigBuffer x22 = 0x0000000000000000 x23 = 0x0000000000000000 x24 = 0x0000000000000000 x25 = 0x0000000000000000 x26 = 0x0000000000000000 x27 = 0x0000000000000000 x28 = 0x0000000000000000 fp = 0x000000016fdff510 lr = 0x000000010001108c dyld`start + 520 sp = 0x000000016fdff3a0 pc = 0x0000000100003f40 add`main + 56 at add.c:13:23 cpsr = 0x60001000
ここで、途中のところでレジスタのところを抜粋すると、 x8
に0x7c(10進数で124)
、x9
に 0x1c8(10進数で456
となっていることがわかります。
... x8 = 0x000000000000007c x9 = 0x00000000000001c8 ...
そして、j = i + j
の計算が終わると、x8
にその計算結果である0x244(10進数でいうと580)
が格納されているのがわかります。
オペコードadd
により、x8
の値のみ変わりますが、x9
の値は変更がないのでそのままとなっていることが確認できます。
x8 = 0x0000000000000244 x9 = 0x00000000000001c8
今回やっていないこと
今回はlldbの使い方の簡単な整理が目的のため、下記の項目については取り掛かっていないですが、別途時間があればまとめようかと思います。