3.6控制
3.6.1条件码
l 除整数寄存器外,CPU还有一级单位个条件码,其中最有用的条件码是:
CF:进位标志,可以用来检测无符号操作数溢出
ZF:零标志
SF:符号标志,最近的操作得到的结果为负数
OF:溢出标志,最近操作导致一个二进制实在溢出——正溢出或负溢出
例如,addl指令完成簮于C表达式t=a+b的功能,这里变量a、b、t都是整型,条件码的设置如下:
CF:(unsigned t)<(unsigned a) 无符号溢出
ZF:(t==0 ) 零
SF:(t<0) 负数
OF:(a<0 == b<0) && (t<0 != a<0) 有符号溢出
l Leal指令不改变任何条件码,因为它是用来做地址计算的,另外,一、二元操作指令都会设置条件码;对于另外一些指令:cmp test只设置条件码,而不改变任何其他寄存器
3.6.2访问条件码
访问条件码的方式最常用的有两种,并不是直接读,而是根据条件码的某个组合,设置一个整数寄存器或是执行一条件分支指令。特别记住的是set指令族,它和前面mov族一样,有很多兄弟:
(桔红色和天蓝色分别用于有符号和无符号)
sete D D=ZF
setne D D=~ZF
sets(负数) D D=SF
setns D D=~SF
有符号数的比较,如cmp $a,$b ,是利用a-b然后得出结果,由于是有符号数,因此会有四种情况出现:1、无溢出,结果为正或0,2、无溢出,结果为负或0,3、有溢出,结果是一个很大的正数,4、有溢出,结果是一个很小的负数;因此可以看出这一个操作将涉及三个标志:有符号溢出OF、0标志ZF、符号标志SF
setg D D=~(SF|OF)&~ZF
setge D D=~(SF^|OF)
setl D D=SF^|OF
setle D D=(SF^OF)|ZF
无符号比较,由于没有符号,因此在其合理表示范围内也不存在负数(因此也就不涉及SF了),所以其结果只有两种:正数或负数(这里的负数即是溢出了),当得到的结果差为负数时,cmp指令会设置进位标志,用以标识无符号数的溢出,因此会使用进位标志CF和零标志OF组合表示最终比较结果
seta(超过) D D=~CF&~ZF
setae D D=~CF
setb(低于) D D=CF
setbe D D=CF|ZF
3.6.3跳转指令和它们的编码
l 跳转指令有直接和间接跳转,分别对应于jmp label、jmp *Operand。直接跳转表示跳转目标是作为指令的一部分编码的;间接跳转,指跳转目标是从寄存器或存储器位置中读出的。条件指令只能是直接跳转。
l Jmp指令也有很多兄弟,其兄弟形式如set,例如:je jne ……
l 跳转指令有几种编码,但是常用的是PC相关的代码,汇编时,它们会将目标指令与跳转指令之后的指令地址差为作编码。如下汇编代码:
8:7e 11 (jmp 指令)
a: 8d b6 00 00 00 00(紧随jmp指令的后一条指令)
……
可以看到地址0x8中,0x7e代表jmp指令,那么上面的汇编代码告诉我们的信息便是jmp将要跳转的地址为0x11 + 0xa = 0x1b。所以可以看到,所谓的PC相关(PC是程序计数器,可以得到下一条将执行的指令,这里温习一下,有助于理解“PC相关”这个概念)工作方式是指,汇编时首先得到jmp将要跳转的目的地址,然后用目的地址减去jmp指令的下一条指令(这就是为什么它和PC有关了)的地址,这个差就做为jmp指令的参数。