我当时正在帮助我的一个朋友进行一些计算机体系结构理论练习。我们偶然发现了这个麦当劳练习一下FLAGS寄存器,而实际上并不知道如何回答。它是这样的:
”假定您在两个无符号整数之间执行了ADD操作,并导致以下标志设置:CF = 0; OF = 1; ZF = 0; SF = 1。这个设置,为什么?”
正确的选择指出该操作的结果是正确的,并在说出原因时指出“因为CF等于零”。我的问题是,为什么当其他标志设置为一个时,为什么只需要考虑进位标志?而且,当我们在无符号整数之间执行加法运算时,如何将溢出和有符号标志设置为1?
谢谢!
答案 0 :(得分:1)
CF = 0告诉您ADD没有包装。参见this article on Understanding Carry vs. Overflow conditions/flags 。
您可以说ADD总是给出正确的(a + b) modulo 2^32
结果,除非您的计算机坏了。如果将ADD环绕,则结果与两个输入的无限精度数学和不同,但它是正确的模运算(免费进行模运算)。因此,您必须小心“正确”的含义! (显然,在这种情况下,您的分配是指数学整数总和。)
此处的术语令人困惑,因为“算术溢出”作为一般概念(当数学上精确的结果不能满足目标要求时)包括有符号和无符号整数。在x86上(像所有普通CPU一样),该行为是可绕行的。但是,无符号环绕称为进位,而有符号环绕称为溢出。
对于浮点,正常的溢出行为是饱和到+/- Infinity。这说明了作为一般概念的溢出和作为整数溢出的特定行为的回绕之间的区别。
某些体系结构具有饱和加法指令,其饱和度是整数溢出行为。 x86具有paddusw
指令(和带符号的版本),用于整数SIMD,但不适用于标量GP寄存器(例如EAX)。
在C语言中,定义了无符号溢出以进行环绕,但是有符号溢出是未定义的行为(编译器可以在假设不发生的情况下进行优化)。
MIPS具有add
指令,可捕获有符号溢出。 (尽管C编译器通常对所有内容使用addu
,因为MIPS是2的补码机,因此它的二进制操作相同,只是捕获行为不同。他们只能安全地使用add
来捕获带符号溢出的UB。当它们添加匹配的变量值(而不是优化之后)时,这些变量将在C抽象机中发生,并且某些bithack代码不安全地依赖于C中的带符号环绕,因此用户通常希望环绕而不是陷阱。MIPS没有FLAGS可以进行任何形式的注册,因此,他们决定如何为溢出检查的加法提供硬件支持。)
其中一些很少/永远不会有用,但这是我对“你能得出什么结论?”的回答。
ZF = 0会告诉您结果不为零。如果要实现if (a + b != 0)
之类的东西,则可以在ADD设置的标志上分支(或cmov或setcc),而不必执行单独的test eax,eax
。除了cmp或test以外,在遵循其他说明后使用ZF并不是很罕见。
SF = 1告诉您结果是> =最大值的一半。即未签名的结果设置了高位。对于8位ADD,SF = 1表示结果> = 128。 有时这可以为您节省测试或比较说明。如果要向其自身添加一个寄存器作为左移,则CF将移出该位,而SF将具有当前的高位。我想OF会告诉您有关
的信息OF = 1(SF = 1和CF = 0)告诉您两个输入均小于最大无符号值的一半。 (即,如果将其解释为带符号的数字,则为正。对结果的带符号的解释为负,因此结果的带符号的解释为pos + pos = neg,这只能通过溢出来发生。)
在我编写的任何汇编中,我都没有利用过最后一个,似乎不太有用。我所知的架构都没有同时考虑CF和OF的分支条件。因此,仅当您已经在CF = 0分支中时,它才有用。 x86已签署了更多(或更少)分支that check SF != OF,但是您仍然无法通过一条指令来检查SF == 1和OF == 1。因此,如果您想检查该条件,那么可能会OR
的两个输入并检查其SF。
答案 1 :(得分:0)
进位标志反映了从操作的最高有效位产生进位。对于无符号操作数,这种进位将反映溢出。
对于其他标志,符号标志仅适用于带符号的操作数。对于溢出标志也是如此,因为当由于有符号操作的溢出而导致符号错误更改时,会置位它。
当结果为零且与溢出检测无关时,将设置最终标志零。
在您呈现的示例中,操作数是无符号的,并且清除了进位标志。因此没有发生溢出。