关于OF和CF
很久很久前写的。越来越意识到作为一名科班出身的学生的重要性。
自己在使用IDA时,发现F5产生类似的这种代码。
其中有一句,v5 <= -141920797,我在想为什么是负数。如果把-141920797化为16进制,如下图:
为什么不是比较的无符号数0xab3f35e3?
看一下对应的汇编代码,如下图:
那么什么是BGT呢?在ARM指令中,有BGT和BHI,感觉都是"大于时跳转"的意思啊,区别在哪里呢?BGT是有符号比较分支指令,BHI是无符号比较分支指令。因此,IDA的F5会将0xab3f35e3当作有符号数来显示。
顺便说一下汇编指令是根据什么判断结果呢?当然是根据N,Z,C,V这些符号标志了。那么什么情况下BGT会跳转呢?如果Z+(N^V)==0,那么就BGT就会跳转。
那么这个Z+(N^V)该怎么理解呢?N就是Negative的意思,如果两个数运算结果的最高位是1,那么就将Negative置为1. V 是Overflow的意思,如果两个数运算结果发生了溢出,那么就会将V置为1.
CPU如何判断是否将V置为1呢?这就涉及到了CPU的溢出判断,CPU的溢出判断不是像我们通过手算判断出运算结果是否超出能表示的范围来判断溢出的。
首先要标明的是,CPU里只有加法器而没有减法器,你看到的SUB指令,CMP指令看似是减法,到CPU里其实做的还是加法运算。使用如下的公式:
[A+B]补 = [A]补 + [B]补
[A-B]补 = [A]补 + [-B]补
[-B]补由[B]的补连同符号位在内,每位取反,末位加1可得。
定点补码运算判断溢出有两种方法,包括由一位符号位判断溢出和由两位符号位判断溢出。我在这里讲一下使用一位符号为判断溢出。结论如下:
由于减法运算在机器中是用加法器实现的,因此可以得出如下结论:不论是作加法还是作减法,只要实际参加操作的两个数(减法时即为被减数和"求补"以后的减数)符号相同,结果又与原操作数符号不同,即为溢出。事实上,CPU也就是这么做的。
到了现在,我们再来理一下为什么Z+(N^V)==0,那么就BGT就会跳转。当N=0,V=0,也就是运算的结果是非负数并且没有溢出,这个时候如果Z=0,那么结果就是正数,BGT就会跳转。当N=1,V=1也就是运算的结果是负数而且发生了溢出,既然发生了溢出,那么运算的结果应该是非负数,而非N=1表示的负数,这个时候如果Z=0,那么结果就是正数,BGT就会跳转。其他的情况也是类似的,在这里不再分析。
顺便说下Carry flag,这个flag有点特殊,在不同的处理器家族中有不同的处理方法。在x86的处理器中,如果是加法指令而且发生了进位,则设Carray flag为1,否则设为0;如果是减法指令,刚才说过了减法指令做的还是加法运算,这个时候发生了进位却将Carray flag设置为0,否则设置为1。在StackOverflow上有关于这的一个讨论。
http://stackoverflow.com/questions/12237725/carray-flag-in-substraction/