在彙編中,CMP和JMP指令常常用于比較操作,而且檢視反彙編源碼時也發現不管是.IF僞指令還是其他的底層都是用CMP實作的。
指令格式:
CMP 目的操作數,源操作數
計算機在遇到CMP指令的時候,CPU将目的操作數和源操作數做減法(即目的操作數-源操作數)進而根據運算結果修改标志位(如OF, CF , ZF, SF等)的值,然後接下來用相應的跳轉指令來進行選擇執行哪一段代碼
另外,操作數有無符号是個頭疼的事情,CPU并不能确定它運算的是有符号的減法還是無符号的減法,是以CPU會産生兩套标志位。
由于我學的不是很深,下面隻是簡單的讨論一下CMP指令執行後标志位的結果(有錯誤請指出)
ZF: 置零标志位,當結果為0的時候ZF被指派1
SF:負數标志位,當結果是負數的時候被指派1
CF:進位/借位标志位,當最高位向它的上一位有借位或者進位的時候被指派1
OF:溢出标志位,當有益處時(即運算結果超過了它的類型(如BYTE, WORD, DWORD)所能表示的範圍)被指派1
溢出的說明:兩個正數相加,兩個負數相加,正數減負數,負數減正數 都有可能溢出
正數溢出變負數,負數溢出變正數
1:無符号數的比較
目的操作數 < 源操作數 ZF=0CF=1JB,JNAE
目的操作數 = 源操作數 ZF=1CF=0JE,JZ
目的操作數 > 源操作數 ZF=0CF=0JA,JNBE
2:有符号數的比較
目的操作數 < 源操作數 ZF=0SF=1OF=0JL
ZF=0 SF=0 OF=1
目的操作數 > 源操作數 ZF=0SF=0OF=0JG
ZF=0 SF=1 OF=1
目的操作數 = 源操作數 ZF=1JE
另外在之前一直對CMP指令和之後的跳轉指令的順序模糊不清,現在也記錄一下
MOV EAX, 0
CMP EAX, VAL1
JBE FINISH
INC EAX
FINISH:
INC EAX
當比較EAX 和VAL1的值之後,
如果EAX <= VAL1 則跳轉到FINISH将EAX加1,最後EAX=1.
如果EAX > VAL1 則不跳轉 執行inc eax ,此時EAX=1, 随後CPU并不是跳過FINISH語句塊,而是接着FINISH的語句繼續執行,是以還會執行一個INC EAX,最後EAX=2
想說明的一點就是CPU的指令時按順序一句一句執行的,除非遇到像JMP 或者CALL 之類的語句會實作跳轉。上述例子中EAX > VAL1時沒有實作跳轉,是以依舊是一步一步繼續執行。
是以如果想實作EAX和VAL1比較 大于則将eax指派1,小于則不變,可以使用短路跳轉法
CMP EAX, VAL1
JBE FINISH
MOV EAX, 1
FINISH:
...........
如果想要用JA的話
CMP EAX, VAL1
JA Larger
JMP FINISH //此處需要告訴CPU跳過Larger語句 不執行大于時的操作
Larger:
MOV EAX,1
FINISH:
...........
就需要在JA跳轉後直接跳過Larger, 因為如果沒有JMP FINISH語句,當不滿足JA(即EAX > VAL1) CPU會繼續執行後面的語句Larger 是以最後不管EAX和VAL1的大小關系如何
EAX都被指派1。