JCC(Jump on Condition Code)指的是條件跳轉指令,c++中的就是if-else, while, for 等分支循環條件判斷的邏輯。它包括很多指令集,各自都不太一樣,接下來我盡量將每一個指令的c++ 源碼和匯編代碼結合起來看,加深學習映像。
學習這章之前還是要了解 EFL 標記寄存器的知識:?匯編學習之《標志寄存器》-CSDN博客
以上標志寄存器部分重點看下? CF,ZF,SF,OF,PF.
理解下面的意思:
cmp x,y?
x -y ==> 影響 CF, ZF 標記位??
情況1? x == y , 計算結果是0, 那么 ZF == 1
情況2? x > y,? 計算結果不是0,那么 ZF == 0
情況3 x <? y , 計算結果不是0,但是會發生錯位,所以? ZF != 0? and??CF ==? 1
JE/JZ (ZF ==1? )
測試:cmp + je? ==> c++ !=? 運算
je: jump if equal? ?
je: jump if zero
判斷 ZF ==1 (cmp 計算的結果是0,兩個值相等情況)
je 和 jz 在OD上是一樣的, 你可以嘗試輸入jz,但是OD會將其替換成JE
匯編代碼
mov DWORD PTR [ebp-0xc], 0x1
mov DWORD PTR [ebp-0x10],0x2
mov eax,DWORD PTR [ebp-0xc]
cmp eax,DWORD PTR [ebp-0x10]?
je 0x401661 <main()+81>???//變量1 == 變量2則跳轉走,c++代碼就必須是 變量1 != 變量2
我們解釋下上面匯編的代碼
第一行: 分配了一個變量地址是ebp-0xc,并賦值是1
第二行: 分配了一個變量地址是ebp-0x10,并賦值是2.
第三行: 將第一個地址的值賦值給EAX 累計寄存器
第四行:?EAX累計寄存器的值(也就是第一個變量的值)減去第二個變量的值。如果為0,則EFL的ZF標記就會被設置成1,否則為0
第五行: 判斷ZF標記是否是1,如果是則調整到main函數的0x401661位置,準備清理資源退出。
c++ 代碼
這里可以對照這個c++代碼
#include <iostream>
int main() {
? ? // JE / ZF 比較相等
? ? int a = 1;? //mov DWORD PTR [ebp-0xc], 0x1
? ? int b = 2; //mov DWORD PTR [ebp-0x10],0x2
? ? //mov eax,DWORD PTR [ebp-0xc]
? ? //cmp eax,DWORD PTR [ebp-0x10]? ? //je 0x401661 <main()+81>
? ? if(a != b)?{
? ? ? ? std::cout << "a == b" << std::endl;
? ? }
? ? return 0;
}
上面的例子我們先看了匯編語言,?大家應該會發現一個問題, 匯編中跳轉的地方指令是je, 也就是比較的兩個對象相等(cmp 指令結果是0, zf==1)情況就跳轉走了。
JNE/JNZ (ZF == 0? 使用c++ ==)
測試:cmp + jne/jnz => c++? ==? 運算
jne: jump if not equal
jnz: jump is not zero
就是判斷 ZF == 0?
jne/jnz 是滿足zf ==0就跳轉,也就是cmp運算結果不是0,也就是兩個變量是一定不相等(a? != b)就會跳轉, c++分支想執行就必須是和a !=0? 條件相反, 那么c++ 代碼就必須變成 a == 0
修改后c++ 代碼
對應的匯編代碼:
可以將JE/JZ 例子中的c++代碼改成a == b 就可以看到了。
JB/JNAE/JC (CF == 1 )
測試:cmp + JB/JNAE/JC? ==>? c++? >=? 運算
jb: jump if below? (無符號比較 低于)
jnae: jump not above or equal?
jc: jump if is carry
判斷 CF == 1
同以上匯編反向推導c++代碼:
第一步: 定義一個變量,賦值為2, 我們定義變量名稱為a
第二步: 定義一個變量, 賦值為1? ?我們定義變量名稱為b
第三步: 比較兩個變量
但是怎么寫呢? 我先看看 匯編指令是jb ,按照這個跳轉指令的的規則,它是判斷CF ==1。如果發生了進位或則錯位, CF == 1那么就滿足條件,就跳轉到mian函數401661的地址處。
要滿足這個要求,就必須是變量a小于變量b(a < b),這樣減法cmp計算才會發生借位。c++代碼這里也就是一個判斷條件,返回過來它是不希望跳轉走,是希望順序執行的,那么c++代碼就必須和剛剛匯編跳轉指令相反,也就是a < b相反, 那么就是 a >= b?
以下是c+代碼
JNB / JAE / JNC (CF == 0)
測試:cmp + JNB / JAE / JNC == > c++? <? 運算
jnb: jump if not below
jae: jump if above or equal
jnc: jump if not carry
判斷 CF == 0
這就簡單思考下,我c++代碼要怎么改,才能驗證 JNB/JAE的指令呢?
首先CF == 0,? 說明 cmp 指令沒有發生借位,也就是 a >= b 這種情況,那么就會跳轉執行,我們c++代碼要執行分支內的代碼,就是不希望跳轉走,所以就必須相反, 那么就是和 a >=? b條件相反,也就是a < b, 那么我改動代碼驗證下,看看c++代碼條件比較語句變成a <? b后, 匯編指令是否是??JNB / JAE / JNC.
改動的c++ 代碼
匯編代碼確認
以上符合預期
JBE / JNA (CF == 1 or ZF == 1 )
測試:cmp + jbe/jna ==> c++ > 運算
jbe: jump if above or equal? ?<=??
jna: jump if not above? ?不大于
判斷??CF == 1 or ZF == 1
匯編運算
c++ 代碼
JA / JNBE (CF == 0 and ZF == 0)
測試:cmp + ja/jnbe ==> c++ <= 運算
ja:? jump if above? ? >
jnbe: jump if not below or??equal? ?不小于不等于
判斷 CF == 0 and ZF == 0
匯編代碼:
c++代碼:
JL / JNGE (SF ≠ OF)
jl: jump if less
jnge: jump if not greater or equal
sf: 當前計算語句是負數,sf =1
of: 當前計算語句發生了溢出? of =1
判斷 SF ≠ OF??不同情況分析:
情況1?sf == 1 and? of ==0
SF == 1 計算結果為負數, OF == 0 沒有發生溢出
a = -5, b = 3
a - 3 = -8? sf =1? of=0, 但是沒有發生溢出。
c++ 代碼
這里按照上面我們的理解, 匯編要滿足小于就跳轉走,那c++ 代碼要反著寫,變成 >=
對應的匯編
情況2: sf == 0? and of == 1
sf == 0 計算結果不是負數, 但是 of ==1 意思是發生了溢出
在看下面代碼前,思考下,什么情況下 cmp 減法操作計算結果不是負數,但是發生了溢出?
以32為舉例: 32位有符號的整數表示的數據返回是-2147483648--2147483647
a =?-2147483648,? b = 1
a - b =?2147483647 //負溢出了 但是計算結果是正數
所以: sf == 0? and of == 1
c++代碼:
對應匯編:
JNL / JGE (SF = OF)
jl: jump if not less
jnge: jump if greater and equal
sf: 當前計算語句是負數,sf =1
of: 當前計算語句發生了溢出? of =1
判斷??SF = OF
情況1 結果是負數,并且發生溢出
a = 5, b = 6?
cmp a,b? ==> sf =1, of =1?
c++ 代碼
匯編代碼:
情況2: 計算結果不是負數,且沒有發生溢出。
JLE / JNG ( SF ≠ OF? ?or? ?ZF == 1)
jle: jump if less or equal
jng: jump if not greater
判斷? (SF ≠ OF)? ? or? ?ZF == 1
情況1?sf == 1 and? of ==0
SF == 1 計算結果為負數, OF == 0 沒有發生溢出
a = -5, b = 3
a - 3 = -8? sf =1? of=0, 但是沒有發生溢出。
c++ 代碼
匯編
情況2 ZF == 1
c++
匯編:
JG / JNLE (?SF == OF?and ZF == 0)
jg: jump if greater
jnle: jump if not less or equal
判斷?(SF == OF) and ZF == 0
?計算結果是負數, 并且發生溢出
a =?2147483647? ?b = -1
cmp a,b
匯編:
JO (OF = =1)
jo: jump if overflow
判斷 OF = =1
溢出情況比較好驗證,但是反推c++ 代碼我還沒有實現,后面生深入了后在來補充。
JNO (OF == 0)
jo: jump if not overflow
判斷 OF == 0
反推c++ 代碼我還沒有實現,后面生深入了后在來補充。
JS (SF == 1)
js: jump if sign
判斷 SF == 1
反推c++ 代碼我還沒有實現,后面生深入了后在來補充。
JNS (SF == 0)
jns: jump if not sign
判斷 SF == 0
反推c++ 代碼我還沒有實現,后面生深入了后在來補充。
JP / JPE (PF ==1)
jp: jump if parity (奇偶校驗事件)
jpe: jump if parity Event (奇偶校驗事件)
判斷? PF ==1 表示數據里面的二進制數,1的個數是偶數的情況
JNP / JPO (?PF == 0)
jnp: jump if not parity
jpo: jump if pariry odd (奇數)
判斷? ?PF == 0 表示數據里面的二進制數, 1的個數是奇數
上一篇:?匯編學習之《jmp, nop指令》
下一篇:匯編學習之《call, return指令》