gccでのループ処理のアセンブリを見てみる
cの実装
簡単なループ処理です。
int main(void) { int r = 0; for (int i = 0; i < 10; i++) { r++; } return r; }
gccでコンパイル
↓のようにコンパイルします。
gcc -S -masm=intel test.c
-S
オプションをつけるとアセンブリソースファイルを作成してくれます。
アセンブルは行いません。
-masmオプションでアセンブリの方言を指定することができます。
ここではintel記法を指定しています。
筆者の環境ではデフォルトだとAT&T記法になるようでした。
出力結果
.file "test.c" .intel_syntax noprefix .text .globl main .type main, @function main: .LFB0: .cfi_startproc push rbp .cfi_def_cfa_offset 16 .cfi_offset 6, -16 mov rbp, rsp .cfi_def_cfa_register 6 mov DWORD PTR [rbp-4], 0 mov DWORD PTR [rbp-8], 0 jmp .L2 .L3: add DWORD PTR [rbp-4], 1 add DWORD PTR [rbp-8], 1 .L2: cmp DWORD PTR [rbp-8], 9 jle .L3 mov eax, DWORD PTR [rbp-4] pop rbp .cfi_def_cfa 7, 8 ret .cfi_endproc .LFE0: .size main, .-main .ident "GCC: (GNU) 7.3.1 20180712 (Red Hat 7.3.1-9)" .section .note.GNU-stack,"",@progbits
ローカル変数
- 変数
r
DWORD PTR [rbp-4]
- 変数
i
DWORD PTR [rbp-8]
ローカル変数はスタック領域にスタックされている。
ラベル
全て接頭辞.L
が付けられています。
.L
があるとラベルがファイルスコープになります。
for文の制御構造がどのラベルに対応しているか
- 初期化式
.LFB0
の末尾
- 条件式
.L2
の頭
- forブロック内のプログラム
.L3
の頭
- 再設定式
.L3
の末尾
初期化式
for (int i = 0; i < 10; i++)
のint i = 0
の部分。
mov DWORD PTR [rbp-8], 0 jmp .L2
変数i
に0を入れています。
初期化が終わってすぐに.L2
にジャンプします。
条件式
for (int i = 0; i < 10; i++)
のi < 10
の部分。
.L2: cmp DWORD PTR [rbp-8], 9 jle .L3
変数i
を9と比較して9以下であれば.L3
にジャンプするという命令です。
比較命令cmpは引数の二つの値を比較します。
比較命令の結果はフラグレジスタにセットされます。
jle
はフラグレジスタの値を評価して比較の結果が等しいかそれより小さい場合に指定した位置にジャンプするという命令です。
ブロック内の処理と再設定式
{r++;}
とfor (int i = 0; i < 10; i++)
のi++
の部分。
.L3: add DWORD PTR [rbp-4], 1 add DWORD PTR [rbp-8], 1
変数r
に1を足してます。
変数i
に1を足してます。
順番はブロック内の処理->再設定式です。