比較的實現
我們知道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) |
這里有好多相等的指令(啊哈,這里有一個有意思的現象,好多看似不沾邊的東西實際上是相等的!),我猜是因為編譯器編譯起來就更方便了,不過做一個表也沒什么難的,這個結論不成立啊……
這里有一點要指出,無符號數用低於、高於來比較,而有符號數用大於、小於比較。