概要
「独習アセンブラ」を読んでアセンブラを学んでいて、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プログラムを作成する
「独習アセンブラ」のサポートページに記載されている、サンプルコードの通りに作成します。
github.com
ここでは、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;
}
本に記載されている通りに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
qiita.com
gcc -g -fno-pic -fomit-frame-pointer -o add add.c
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
frame
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
の両方を指定する必要があるとのことだったのでそのまま指定しています。
stackoverflow.com
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によるデバッグを実行します。
ここではcのソースコードの所定の行にブレークポイントを貼り、デバッグモードで実行し、それぞれのブレークポイントで下記の内容を確認します。
- 実行ファイルから逆アセンブルし、アセンブリコードレベルでのデバッグ
- レジスターの内容の確認
前述でやったのと同じ感じで、lldbを起動し、ブレークポイントを張っていきます。
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
frame
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
下記のように簡単に書けます。
(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
frame
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
frame
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
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,
0x100003f0c <+4>: stp x29, x30, [sp,
0x100003f10 <+8>: str wzr, [sp,
0x100003f14 <+12>: mov w8,
0x100003f18 <+16>: str w8, [sp,
0x100003f1c <+20>: ldr w8, [sp,
0x100003f20 <+24>: add w8, w8,
0x100003f24 <+28>: str w8, [sp,
0x100003f28 <+32>: mov w8,
0x100003f2c <+36>: str w8, [sp,
-> 0x100003f30 <+40>: ldr w8, [sp,
0x100003f34 <+44>: ldr w9, [sp,
0x100003f38 <+48>: add w8, w8, w9
0x100003f3c <+52>: str w8, [sp,
0x100003f40 <+56>: ldr w9, [sp,
0x100003f44 <+60>: mov x8, x9
0x100003f48 <+64>: adrp x0, 0
0x100003f4c <+68>: add x0, x0,
0x100003f50 <+72>: mov x9, sp
0x100003f54 <+76>: str x8, [x9]
0x100003f58 <+80>: bl 0x100003f6c
0x100003f5c <+84>: ldr w0, [sp,
0x100003f60 <+88>: ldp x29, x30, [sp,
0x100003f64 <+92>: add sp, sp,
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,
0x100003f34 <+44>: ldr w9, [sp,
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
frame
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,
0x100003f0c <+4>: stp x29, x30, [sp,
0x100003f10 <+8>: str wzr, [sp,
0x100003f14 <+12>: mov w8,
0x100003f18 <+16>: str w8, [sp,
0x100003f1c <+20>: ldr w8, [sp,
0x100003f20 <+24>: add w8, w8,
0x100003f24 <+28>: str w8, [sp,
0x100003f28 <+32>: mov w8,
0x100003f2c <+36>: str w8, [sp,
0x100003f30 <+40>: ldr w8, [sp,
-> 0x100003f34 <+44>: ldr w9, [sp,
0x100003f38 <+48>: add w8, w8, w9
0x100003f3c <+52>: str w8, [sp,
0x100003f40 <+56>: ldr w9, [sp,
0x100003f44 <+60>: mov x8, x9
0x100003f48 <+64>: adrp x0, 0
0x100003f4c <+68>: add x0, x0,
0x100003f50 <+72>: mov x9, sp
0x100003f54 <+76>: str x8, [x9]
0x100003f58 <+80>: bl 0x100003f6c
0x100003f5c <+84>: ldr w0, [sp,
0x100003f60 <+88>: ldp x29, x30, [sp,
0x100003f64 <+92>: add sp, sp,
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
frame
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,
0x100003f0c <+4>: stp x29, x30, [sp,
0x100003f10 <+8>: str wzr, [sp,
0x100003f14 <+12>: mov w8,
0x100003f18 <+16>: str w8, [sp,
0x100003f1c <+20>: ldr w8, [sp,
0x100003f20 <+24>: add w8, w8,
0x100003f24 <+28>: str w8, [sp,
0x100003f28 <+32>: mov w8,
0x100003f2c <+36>: str w8, [sp,
0x100003f30 <+40>: ldr w8, [sp,
0x100003f34 <+44>: ldr w9, [sp,
-> 0x100003f38 <+48>: add w8, w8, w9
0x100003f3c <+52>: str w8, [sp,
0x100003f40 <+56>: ldr w9, [sp,
0x100003f44 <+60>: mov x8, x9
0x100003f48 <+64>: adrp x0, 0
0x100003f4c <+68>: add x0, x0,
0x100003f50 <+72>: mov x9, sp
0x100003f54 <+76>: str x8, [x9]
0x100003f58 <+80>: bl 0x100003f6c
0x100003f5c <+84>: ldr w0, [sp,
0x100003f60 <+88>: ldp x29, x30, [sp,
0x100003f64 <+92>: add sp, sp,
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
frame
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
frame
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,
0x100003f0c <+4>: stp x29, x30, [sp,
0x100003f10 <+8>: str wzr, [sp,
0x100003f14 <+12>: mov w8,
0x100003f18 <+16>: str w8, [sp,
0x100003f1c <+20>: ldr w8, [sp,
0x100003f20 <+24>: add w8, w8,
0x100003f24 <+28>: str w8, [sp,
0x100003f28 <+32>: mov w8,
0x100003f2c <+36>: str w8, [sp,
0x100003f30 <+40>: ldr w8, [sp,
0x100003f34 <+44>: ldr w9, [sp,
0x100003f38 <+48>: add w8, w8, w9
0x100003f3c <+52>: str w8, [sp,
-> 0x100003f40 <+56>: ldr w9, [sp,
0x100003f44 <+60>: mov x8, x9
0x100003f48 <+64>: adrp x0, 0
0x100003f4c <+68>: add x0, x0,
0x100003f50 <+72>: mov x9, sp
0x100003f54 <+76>: str x8, [x9]
0x100003f58 <+80>: bl 0x100003f6c
0x100003f5c <+84>: ldr w0, [sp,
0x100003f60 <+88>: ldp x29, x30, [sp,
0x100003f64 <+92>: add sp, sp,
0x100003f68 <+96>: ret
(lldb) di
add`main:
0x100003f08 <+0>: sub sp, sp,
0x100003f0c <+4>: stp x29, x30, [sp,
0x100003f10 <+8>: str wzr, [sp,
0x100003f14 <+12>: mov w8,
0x100003f18 <+16>: str w8, [sp,
0x100003f1c <+20>: ldr w8, [sp,
0x100003f20 <+24>: add w8, w8,
0x100003f24 <+28>: str w8, [sp,
0x100003f28 <+32>: mov w8,
0x100003f2c <+36>: str w8, [sp,
0x100003f30 <+40>: ldr w8, [sp,
0x100003f34 <+44>: ldr w9, [sp,
0x100003f38 <+48>: add w8, w8, w9
0x100003f3c <+52>: str w8, [sp,
-> 0x100003f40 <+56>: ldr w9, [sp,
0x100003f44 <+60>: mov x8, x9
0x100003f48 <+64>: adrp x0, 0
0x100003f4c <+68>: add x0, x0,
0x100003f50 <+72>: mov x9, sp
0x100003f54 <+76>: str x8, [x9]
0x100003f58 <+80>: bl 0x100003f6c
0x100003f5c <+84>: ldr w0, [sp,
0x100003f60 <+88>: ldp x29, x30, [sp,
0x100003f64 <+92>: add sp, sp,
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の使い方の簡単な整理が目的のため、下記の項目については取り掛かっていないですが、別途時間があればまとめようかと思います。