条件跳转指令Jcc(Jump condition code)
关于条件跳转指令,特别是用于有符号数比较的Jcc指令,网上的文章多有讹误,这次彻底的厘清一下,以备忘。
在介绍条件跳转指令之前,介绍一下EFLAGS寄存器中的状态标志(Status Flag)是有必要的,Jcc中的cc(condition code)即表示需要测试的状态标志或状态标志组合。EFLAGS寄存器的低16位在8086时代叫做FLAGS寄存器,又称作程序状态字PSW(Program Status Word)。
这些状态标志指示了算术运算指令的运算结果,分别介绍如下:
- CF(bit 0) 进位标志 - 当运算结果的最高有效位发生进位或借位的时候该标志位置位,否则复位。这个标志指示了无符号数运算的溢出条件。它同样用于多精度算术运算。
- PF(bit 2) 奇偶标志 - 运算结果的最低有效字节如果包含偶数个1,那么该标志置位,否则复位。请注意是最低有效字节而不是整个运算结果。
- AF(bit) 调整标志 - 如果运算结果的位3发生进位或借位,则该标志位置位,否则复位。这个标志位使用在BCD(binary-coded decimal)码的算术运算中。
- ZF(bit 6) 零标志 - 如果运算结果是零则置位,否则复位。
- SF(bit 7) 符号标志 - 与运算结果的最高有效位相同。
- OF(bit 11) 溢出标志 - 如果运算结果对于一个正数来说太大或者对于一个负数来说太小而不能用与目标操作数等位宽的数来表示的时候,也就是超出了n位(目的操作数的位数)有符号数表示的范围则置位,否则复位。这个标志指示了有符号数算术运算的溢出条件。
这些状态标志允许仅使用一个算术运算操作为三种不同的数据类型产生结果,这三种数据类型为无符号整数,有符号整数和BCD编码的整数。如果将运算结果看做一个无符号数,那么CF标志指示运算超出范围,有进位或借位发生。如果将运算结果看做一个有符号数,那么OF标志指示有进位或借位发生。如果将运算结果看做一个BCD数,那么AF标志指示有进位或借位发生。也就是说,对于整数运算来说,CPU才不管操作数是什么类型的,操作数是什么类型由你说了算,只要测试不同的标志位就可以了。
下面三张表详细列出了各种Jcc指令
指令
描述
条件
JC rel8/16/32
如果进位标志置位则短/近/近跳转
CF=1
JNC rel8/16/32
如果进位标志复位则短/近/近跳转
CF=0
JP/JPE rel8/16/32
如果奇偶标志置位则短/近/近跳转
PF=1
JNP,JPO rel8/16/32
如果奇偶标志复位则短/近/近跳转
PF=0
JZ rel8/16/32
如果零标志置位则短/近/近跳转
ZF=1
JNZ rel8/16/32
如果零标志复位则短/近/近跳转
ZF=0
JS rel8/16/32
如果符号标志置位则短/近/近跳转
SF=1
JNS rel8/16/32
如果符号标志复位则短/近/近跳转
SF=0
JO rel8/16/32
如果零溢出志置位则短/近/近跳转
OF=1
JNO rel8/16/32
如果零溢出志复位则短/近/近跳转
OF=0
指令
描述
条件
JA/JNBE rel8/16/32
如果高于/不低于或等于则短/近/近跳转
CF=0 and ZF=0
JAE/JNB rel8/16/32
如果高于或等于/不低于则短/近/近跳转
CF=0
JB/JNAE rel8/16/32
如果低于/不高于或等于则短/近/近跳转
CF=1
JBE/JNA rel8/16/32
如果低于或等于/不高于则短/近/近跳转
CF=1 or ZF=1
JE rel8/16/32
如果等于则短/近/近跳转
ZF=1
JNE rel8/16/32
如果不等于则短/近/近跳转
ZF=0
指令
描述
条件
JG/JNLE rel8/16/32
如果大于/不小于或等于则短/近/近跳转
ZF=0 and SF=OF
JGE/JNL rel8/16/32
如果大于或等于/不小于则短/近/近跳转
SF=OF
JL/JNGE rel8/16/32
如果小于/不大于或等于则短/近/近跳转
SF!=OF
JLE/JNG rel8/16/32
如果小于或等于/不大于则短/近/近跳转
ZF=1 or SF!=OF
JE rel8/16/32
如果等于则短/近/近跳转
ZF=1
JNE rel8/16/32
如果不等于则短/近/近跳转
ZF=0
表注释:
- 64位模式下,不支持所有Jcc rel16格式的近跳转指令。
- 对于有符号数的比较使用术语小于”less”和大于”greater”,而对于无符号数的比较使用术语低于”below”和高于”above”
前两张表记载的指令比较直白、简单,不做过多介绍。下面重点介绍一下有符号数比较的Jcc指令。只要解释清楚了JG和JL,其他就很简单了。
n位二进制数来表示有符号数,可以表示的范围为
-2^(n-1) =< X Y OF==SF
再考虑一个负数减一个正数的情况,这种情况下结果肯定是一个负数,如果结果超出了n位有符号数可以标示的范围,则溢出OF=1,而一个负数太小了,则发生了反绕,变成了正数,也就是SF=0
如果结果没有溢出,则OF=0,因为结果是一个负数,所以SF=1
那么
X<Y OF!=SF
如果两个数同号,那么不会溢出OF=0,如果X>Y则结果是正的SF=0,如果X<Y则结果是负的,SF=1
那么
X>Y OF==SF
X<Y OF!=SF
所以两个有符号数XY相减X-Y,最后总结如下:
X>Y也就是JG成立的条件为OF==SF
X<Y也就是JL成立的条件为OF!=SF
其他指令不过是再加上对ZF的判断而已,比较简单。