什么是标志位?
x86架构的CPU中有32位的标志寄存器(eflags),在PA中只关心其中的五个 : ZF(零标志位),SF(符号标志位),OF(溢出标志位),CF(进位标志位),IF(中断标志位)。
ZF 和 SF
ZF(zero flag)用于指示计算结果是否是 0。
SF(sign flag)用于指示计算结果的符号位,显然,我们应将计算结果看做有符号数。
原码,补码和反码
正数 1 0001(原码) 0001(反码) 0001(补码)
负数 -1 1001(原码) 1110(反码) 1111(补码)
有符号数和无符号数
在计算中没有所谓的符号之分,计算机中存储数值用补码来表示,比如四位加法 :1000b + 0001b = 1001b,如果看成无符号数为 8+1=9,如果看成有符号数则是 -8+1=-7,计算机只是简单的将补码按位相加。
但是由于计算机只能存储四位(假设),这样并不能保证计算结果总是正确的。
OF 和 CF
OF(overflow flag)指示无符号数的运算结果是否产生溢出。比如 1111b + 1111b = 1110b,即 15+15=14,显然高位被丢弃导致溢出而使得计算结果不准确。此时OF标志位置1。
CF(carry flag)指示有符号数的运算结果是否产生进位或借位。比如 0111b + 0111b = 1110b,即 7+7=-2,这是由于产生进位使得计算结果不准确。此时CF标志位置1。
溢出和进位(借位)的区别
溢出表示无符号数的运算超出范围(0~15),进位(借位)表示有符号数的运算超出范围(-8~7)。
溢出不一定产生进位(借位),比如上面的 1111b + 1111b = 1110b 产生了溢出,但看做有符号数运算时 -1+-1=-2 计算结果是准确的,并没有进位。
同理,0111b + 0111b = 1110b 虽然产生了进位,但是若看做无符号数 7+7=14,并没有超出范围,结果准确,没有溢出。
SF 和 ZF 判断方法
SF只需判断运算结果的最高有效位
ZF只需判断运算结果是否为0
对于加法指令 add : res = dest + src
若 res < dest 则 溢出
若 dest 与 src 同号,res 变号则 进位
特别的,对于 带进位加法 adc : res = dest + src + carry,分两次加法判断即可,只要其中有一次溢出(进位|借位),那么结果就溢出(进位|借位)。
对于减法 sub : res = dest - src
若 dest < src 则 溢出
若 dest 与 src 符号相反,res 与 src 同号则 进位(将减法考虑为加法)
特别的对于 sbb : res = dest - src - carry,方法同上。
未完待续...