昨天有提到幾個常見的 Assembly Instruction:
mov
add
sub
ret
但如果程式裡面出現:
if
else
while
for
這些條件判斷和迴圈,在 Assembly 裡面又會變成什麼樣子?
今天就來看看:
cmp
jmp
je
jne
先看一段簡單的 C Code:
int check(int a) {
if (a == 10) {
return 1;
}
return 0;
}
前一篇有提過,在 Linux x86-64 中第一個 Function Argument 通常會放在:
RDI
所以 a 通常可以在 EDI 裡面找到
如果要判斷:
a == 10
Assembly 裡面可能會看到:
cmp edi, 10
cmp 可以先簡單理解成:
edi - 10
但它不會把結果存回 edi,而是修改 CPU 裡面的 Flag
其中一個常見的是:
ZF → Zero Flag
例如:
10 - 10 = 0
這時:
ZF = 1
也就代表兩個值相等
有了比較結果之後,就可以決定要不要跳到其他地方
例如:
cmp edi, 10
je .success
其中:
je → Jump if Equal
所以可以理解成:
如果 edi == 10
就跳到 .success
完整一點可能會是:
cmp edi, 10
je .success
mov eax, 0
ret
.success:
mov eax, 1
ret
對照:
if (a == 10) {
return 1;
}
return 0;
可以發現高階語言裡的 if,到了 Assembly 中通常就是:
比較
+
跳轉
常見的 Conditional Jump 還有:
je → Equal
jne → Not Equal
jg → Greater
jge → Greater or Equal
jl → Less
jle → Less or Equal
另外:
jmp
則是不判斷任何條件,直接跳到指定的位置
例如:
int check(int a) {
if (a > 10) {
return 1;
} else {
return 2;
}
}
可能會看到類似:
cmp edi, 10
jle .else
mov eax, 1
ret
.else:
mov eax, 2
ret
這裡:
jle .else
代表:
如果 a <= 10
就跳到 .else
所以可以先簡單記成:
if / else
↓
cmp + Conditional Jump
迴圈其實也是類似的概念
例如:
int i = 0;
while (i < 5) {
i++;
}
簡化成 Assembly 可以想成:
mov eax, 0
.loop:
cmp eax, 5
jge .end
add eax, 1
jmp .loop
.end:
首先比較:
cmp eax, 5
如果:
eax >= 5
就跳到 .end
否則:
add eax, 1
然後:
jmp .loop
再跳回前面繼續執行
因此 while 或 for 可以先簡單理解成:
比較條件
↓
Conditional Jump
↓
執行內容
↓
jmp 回前面
今天可以先記得:
cmp
負責比較兩個值,而:
je
jne
jg
jge
jl
jle
會根據比較結果決定要不要跳轉
所以:
if / else
↓
cmp + Conditional Jump
而:
while / for
↓
cmp + Conditional Jump + jmp
透過這些 Jump,程式就不一定只能按照 Instruction 從上往下執行
前面幾篇也一直有看到:
ret
那 Function 到底是怎麼被呼叫的?
下一篇就來看看 Assembly 裡面的:Function Call