条件转移指令在8086/88汇编语言中占据着重要的地位,它是CPU实现"判断"的基础。通过前面一段的学习我们已经知道,条件转移指令的条件实际上都来自于标志寄存器。所以原则上说除了TF、IF、DF等用于控制CPU工作状态的几个标志位没有对应的条件转移指令外,其那些反映运算后果的标志位都应该有相应的条件转移指令。
原则上讲的确应该有这样的规律,不过有个特例--AF标志没有相应的条件转移指令。除AF外,SF、ZF、PF、CF、OF都有对应的条件转移指令。另外有一些条件转移指令要根据几个标志位的情况进行转移,比如前面我们讨论过的指令"JA",还有其它的一些。在本节里我们将总结所有的条件转移指令以及它们所判断的条件。
在总结之前还要先解决一个前面遗留下来的问题,就是指令JA/JB与指令JG/JL的区别。前面已经提到过如果要对符号不同的两个数进行比较,应该使用JG/JL指令判断结果。下面先进行一个实验,实验过程中请注意观察符号标志位SF与溢出标志位OF:
C:\ASM\>DEBUG[Enter] -a[Enter] 0F6A:0100 mov al,5 0F6A:0102 cmp al,3 0F6A:0104 cmp al,-1 0F6A:0106 cmp al,80 0F6A:0108 [Enter] -g=100 102[Enter] AX=0005 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=002A DI=0000 DS=0F6A ES=0F6A SS=0F6A CS=0F6A IP=0102 NV UP EI PL NZ NA PO NC 0F6A:0102 3C03 CMP AL,03
注意在进行数据比较之前SF与OF标志都为0,且CF标志也为0。
-p[Enter] AX=0005 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=002A DI=0000 DS=0F6A ES=0F6A SS=0F6A CS=0F6A IP=0104 NV UP EI PL NZ NA PO NC 0F6A:0104 3CFF CMP AL,FF
第一次我们将+5与+3相比较,各标志位都没有变化。如果单从CF与ZF标志来看是可以说明5>3的,因为此次比较即没有产生借位且结果也不是0。指令JA就是依靠这两个标志位进行判断的。
-p[Enter] AX=0005 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=002A DI=0000 DS=0F6A ES=0F6A SS=0F6A CS=0F6A IP=0106 NV UP EI PL NZ AC PE CY 0F6A:0106 3C80 CMP AL,80
第二次将+5与-1相比较,标志寄存器产生了变化。如果此时仍然通过CF标志对比较结果进行判断,就会有+5<-1的结果,只有小数减大数才会产生借位。由此可以得出这样的结论:CPU在设置CF标志位的时候是不考虑参加运算的数是否有符号的。换句话说,CPU把参加运算的数都看做无符号数。这就是指令JA/JB只适用于无符号数相比较的原因。
那么符号究竟从哪里体现呢?现在我们可以想到的只有符号标志SF位。而且有一个事实是我们每个人都知道的,就是当一个小的数减一个大的数的时候,无论这两个数是否有符号,它们相减的结果必然是负数。也就是说这样两个数相减之后,SF标志应该是1(NG)。
从跟踪的结果来看+5与-1相比较之后SF标志位仍然是0(PL),这说明了+5并不小于-1。由此看来判断带符号数的比较结果应该通过SF标志而不是CF标志。
-p[Enter] AX=0005 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000 SI=002A DI=0000 DS=0F6A ES=0F6A SS=0F6A CS=0F6A IP=0108 OV UP EI NG NZ NA PO CY 0F6A:0108 5F POP DI
是否仅仅通过SF标志就能正确判断带符号数的大小呢?将+5与-128相比较之后我们可以看到SF标志为1(NG)。如果按刚才的推论来看+5应该小于-128,这当然不对。问题出在哪儿?
实际上+5减-128应该得+133,但是+133是大于+127的,所以这样的一次运算其实已经导致了溢出。注意观察OF标志,它悄悄地从"NV"变成了"OV"。所以我们又可以得出一个推论:如果比较之后符号标志SF为1同时溢出标志OF也为1,则仍然说明前一个数不小于后一个数。
综合上面的实验结果,就可以推测出相比较的两个带符号数如果是"前不小于后"的关系,那么符号标志SF与溢出标志OF必然是同为0(+5比+3、+5比-1)或同为1(+5比-128)。再进一步推断,如果这两个数是"前小于后"的关系,那么SF与OF之中必有一个是1,而另一个是0。即要么是结果为负而无溢出,要么是结果为正而有溢出。
究竟是不是这样?多做一些实验就能知道。比如用+3减去+5就能看到结果为负而无溢出的情况。而用-40减去+100就能看到结果为正而有溢出的情况了。总之前面推出的结论是完全正确的。由此我们得出了指令"JL"所判断的条件,把这个条件写成表达式的形式就是"SF XOR OF=1"。
同时指令JG判断的条件也就自然得出,应该是"(SF XOR OF)OR ZF=0",要注意排除两个数相等的情况(ZF=1)。如果不排除两个数相等的情况,即只考虑"SF XOR OF=0",那么相应的指令就应该是"JGE",这个指令在前面讨论画线时应用过。那么指令"JLE"判断的条件又是什么呢?没错,是"(SF XOR OF)OR ZF=1"。
表10-2给出了所有条件转移指令的说明,其中有一些是我们前面没有讨论过的。