匯編條件判斷整理(JCC,CMP/TEST的實現)


比較的實現

我們知道CMP是比較兩個寄存器內容的指令,但這是如何實現的?

當執行到CMP指令的時候會讀取這兩個寄存器的內容,並加以減法運算,結果本身不保留,並按照結果設置符號位(屬算術運算)。

CMP是一個經常使用的指令,大多用來測試數字的大小。一個常見的例子

MOV EAX, 10
MOV EAX, 10
CMP EAX, EBX   ;相減求出結果,為0,將1存入ZF
JE  SOME_WHERE ;檢查ZF,為1就跳
JNE SOME_WHERE ;檢查ZF,為0就跳

當執行到TEST指令的時候會讀取這兩個寄存器的內容,並加以按位與運算,結果不保留,並按照結果設置符號位(屬邏輯運算)。

TEST是一個用來檢測內容而不是運算內容的,經常用的一招是測試寄存器是否為0:

TEST EAX, EAX
JZ   SOME_WHERE

某個參考資料說 TEST EAX,EBX 與 AND EAX,EBX 是一樣的,竊以為不同,因為匯編的所有算術指令都是破壞性的,它會把結果存入 EAX,而TEST不會(就像C代碼 a &= b;)。若要 AND 也不會破壞原值,只能先入棧存值,然后在出棧前轉移結果,就像如下所示:

MOV  EAX, ??  ;賦值
MOV  EBX, ??
PUSH EAX      ;入棧保存EAX
AND  EAX, EBX ;運算
MOV  EDX, EAX ;保存結果
POP  EAX      ;彈出恢復EAX

但是你要自己做一個CMP指令是不切實際的,因為你自己還是要判斷符號位的值,最終還是用到了TEST, CMP這些指令。

符號位表

這些符號位存在一個叫做PSW(Program Status Word,程序狀態字)的16位(4字節)寄存器里面。

符號位 敘述 典型應用
OF 溢出標志,標明一個溢出的運算。真置1,假置0。 這個溢出,非溢出,我想我還沒有弄懂
SF 負號標志,標明結果為負數。真置1,假置0。

int i = -100;

if(i < 0)

goto somewhere;

ZF 零標志,標明結果為0。真置1,假置0。 見上cmp例子
CF 進位標志,標明結果進位了。真置1,假置0。

MOV EAX,1

MOV EBX,9

ADD EAX,EBX

AF 輔助進位標志,記錄運算時第3位(半個字節)產生的進位。 <null>
PF 奇偶標志,結果操作數中1的個數為偶置1(我猜是二進制下)。 <null>
DF 方向標志,在串處理指令中控制信息的方向(非運算) (null)
IF 中斷標志(非運算) (null)
TF 陷井標志(非運算) (null)

其中前幾個稱為運算條件碼(condition code),后三個是邏輯控制標志位,我們在此對它們不感興趣。

JCC指令表

JCC指條件跳轉指令,CC就是指條件碼。

JCC指令 中文含義 英文原意 檢查符號位 典型C應用
JZ/JE

若為0則跳轉;

若相等則跳轉

jump if zero;

jump if equal

ZF=1

if (i == j);

if (i == 0);

JNZ/JNE

若不為0則跳轉;

若不相等則跳轉

jump if not zero;

jump if not equal

ZF=0

if (i != j);

if (i != 0);

JS 若為負則跳轉 jump if sign SF=1 if (i < 0);
JNS 若為正則跳轉 jump if not sign SF=0 if (i > 0);
JP/JPE 若1出現次數為偶數則跳轉 jump if Parity (Even) PF=1 (null)
JNP/JPO 若1出現次數為奇數則跳轉 jump if not parity (odd) PF=0 (null)
JO 若溢出則跳轉 jump if overflow OF=1 (null)
JNO 若無溢出則跳轉 jump if not overflow OF=0 (null)
JC/JB/JNAE

若進位則跳轉;

若低於則跳轉;

若不高於等於則跳轉

jump if carry;

jump if below;

jump if not above equal

CF=1 if (i < j);
JNC/JNB/JAE

若無進位則跳轉;

若不低於則跳轉;

若高於等於則跳轉;

jump if not carry;

jump if not below;

jump if above equal

CF=0 if (i >= j);
JBE/JNA

若低於等於則跳轉;

若不高於則跳轉

jump if below equal;

jump if not above

ZF=1或CF=1 if (i <= j);
JNBE/JA

若不低於等於則跳轉;

若高於則跳轉

jump if not below equal

jump if abow

ZF=0或CF=0 if (i > j);
JL/JNGE

若小於則跳轉;

若不大於等於則跳轉

jump if less

jump if not greater equal

SF != OF if (si < sj);
JNL/JGE

若不小於則跳轉;

若大於等於則跳轉;

jump if not less;

jump if greater equal

SF = OF if (si >= sj);
JLE/JNG

若小於等於則跳轉;

若不大於則跳轉

jump if less equal;

jump if not greater

ZF != OF 或 ZF=1 if (si <= sj);
JNLE/JG

若不小於等於則跳轉;

若大於則跳轉

jump if not less equal

jump if greater

SF=0F 且 ZF=0 if(si>sj)

這里有好多相等的指令(啊哈,這里有一個有意思的現象,好多看似不沾邊的東西實際上是相等的!),我猜是因為編譯器編譯起來就更方便了,不過做一個表也沒什么難的,這個結論不成立啊……

這里有一點要指出,無符號數用低於、高於來比較,而有符號數用大於、小於比較。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM