コース目次 / 第3章
条件分岐とループを読む
for文をコンパイルしたアセンブリを読み、cmp命令とjmp/jle等の条件・無条件ジャンプが、if/forをどう表現するかを追います。実際に行番号を対応づけながらループの構造を読み解きます。
C言語の if や for は、アセンブリでは専用の命令ではありません。比較(cmp)と、条件によって飛び先を変えるジャンプ(j で始まる命令)の組み合わせで表現されます。
標的 — 1からnまで足し合わせる
int sumTo(int n) {
int total = 0;
for (int i = 1; i <= n; i++) {
total += i;
}
return total;
}
gcc -O0 -g -c loop.c -o loop.o
objdump -d -M intel loop.o
0000000000000000 <sumTo>:
0: f3 0f 1e fa endbr64
4: 55 push rbp
5: 48 89 e5 mov rbp,rsp
8: 89 7d ec mov DWORD PTR [rbp-0x14],edi
b: c7 45 f8 00 00 00 00 mov DWORD PTR [rbp-0x8],0x0
12: c7 45 fc 01 00 00 00 mov DWORD PTR [rbp-0x4],0x1
19: eb 0a jmp 25 <sumTo+0x25>
1b: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
1e: 01 45 f8 add DWORD PTR [rbp-0x8],eax
21: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1
25: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
28: 3b 45 ec cmp eax,DWORD PTR [rbp-0x14]
2b: 7e ee jle 1b <sumTo+0x1b>
2d: 8b 45 f8 mov eax,DWORD PTR [rbp-0x8]
30: 5d pop rbp
31: c3 ret
ソースと、対応づけて読む
長く見えますが、C のソースと1行ずつ対応づければ、すっきり読めます。
[rbp-0x14] = 引数 n、[rbp-0x8] = total、[rbp-0x4] = i、と割り当てられています(コンパイラが決めた配置)。
アドレス b, 12 — total = 0; i = 1; の初期化。
アドレス 19 — jmp 25。無条件で、比較を行うアドレス25へ先にジャンプします(for は本体より先に条件を1回確かめる形が定石なので、最初の1回はここで条件チェックへ飛びます)。
アドレス 1b〜21 — ループの本体。total += i;(1b, 1e)、i++(21)。
アドレス 25, 28 — i を eax に読み、cmp eax, [rbp-0x14] で i と n を比較。
アドレス 2b — jle 1b。比較結果が「以下(less or equal)」なら、本体の先頭(アドレス1b)へ戻ってジャンプ。そうでなければ、次の行(2d)へ進み、ループを抜けます。
cmp は、実は「引き算して、結果を覚える」だけ
cmp a, b は、内部的にはa - b を計算していますが、その結果を a に書き戻しません。代わりに、結果が0だったか・負だったか、といった状態を、CPU内部の小さなフラグに記録します。直後に続く jxx 系の命令(je=等しければ、jle=以下なら、jg=より大きければ、など)は、そのフラグを見て、飛ぶか飛ばないかを決めます。cmp と jxx は、常に対で働くペアです。
読み方のコツ — ジャンプ先を、先に丸で囲む
初めて見るアセンブリを読むときのコツです。
1. まず、すべての jmp/jxx 命令の行き先アドレスに印を付ける。今回なら 19→25 と 2b→1b。
2. その印を頼りに、コードを「ブロック」に分ける。ジャンプ先・ジャンプ元は、たいてい意味のある区切り(ループの先頭、条件分岐の分かれ目)です。
3. ブロックごとに「何をしているか」を、C言語のつもりで言語化する。今回なら「初期化」「本体」「条件チェックして戻るか抜けるか」の3ブロックに分かれました。
この手順は、この先どれだけ複雑な関数を読むときも変わりません。
持ち帰る一言
if/forは、cmpとジャンプの組み合わせ。 cmp が比較してフラグを立て、jxx がそれを見て飛ぶ。ジャンプ先に印を付けてブロックに分ければ、初めて見るアセンブリでも制御の流れを再構成できます。次はまとめて、このコースを締めます。
こうなっていればOK
卒業まであと1章です。
この章はまだ完了していません。
保存できませんでした(プライベートブラウズ中かもしれません)。この端末に進捗は残りませんが、先へは進めます。