# 3.6.1 条件码

除了整数寄存器,CPU 还维护着一组单个位的条件码(condition code)寄存器,它们描述了最近的算术或逻辑操作的属性。可以检测这些寄存器来执行条件分支指令。最常用的条件码有:

  • CF:进位标志。最近的操作使最高位产生了进位。可用来检查无符号操作的溢出。
  • ZF:零标志。最近的操作得出的结果为 0。
  • SF:符号标志。最近的操作得到的结果为负数。
  • OF:溢出标志。最近的操作导致一个补码溢出——正溢出或负溢出。

比如说,假设我们用一条 ADD 指令完成等价于 C 表达式 t = a + b 的功能,这里变量 abt 都是整型的。然后,根据下面的 C 表达式来设置条件码:

条件码 C 表达式 含义
CF (unsigned) t < (unsigned) a 无符号溢出
ZF (t == 0)
SF (t < 0) 负数
OF (a < 0 == b < 0) && (t < 0 != a < 0) 有符号溢出

leaq 指令不改变任何条件码,因为它是用来进行地址计算的。除此之外,图 3-10 中列出的所有指令都会设置条件码。对于逻辑操作,例如 XOR,进位标志和溢出标志会设置成 0。对于移位操作,进位标志将设置为最后一个被移出的位,而溢出标志设置为 0。INC 和 DEC 指令会设置溢出和零标志,但是不会改变进位标志,至于原因,我们就不在这里深入探讨了。

除了图 3-10 中的指令会设置条件码,还有两类指令(有 8、16、32 和 64 位形式),它们只设置条件码而不改变任何其他寄存器,如图 3-13 所示。CMP 指令根据两个操作数之差来设置条件码。除了只设置条件码而不更新目的寄存器之外,CMP 指令与 SUB 指令的行为是一样的。在 ATT 格式中,列出操作数的顺序是相反的,这使代码有点难读。如果两个操作数相等,这些指令会将零标志设置为 1,而其他的标志可以用来确定两个操作数之间的大小关系。TEST 指令的行为与 AND 指令一样,除了它们只设置条件码而不改变目的寄存器的值。

指令 基于 描述
CMP S1, S2 S2 - S1 比较
cmpb 比较字节
cmpw 比较字
cmpl 比较双字
cmpq 比较四字
TEST S1, S2 S1 & S2 测试
testb 测试字节
testw 测试字
testl 测试双字
testq 测试四字

图 3-13 比较和测试指令。这些指令不修改任何寄存器的值,只设置条件码

典型的用法是,两个操作数是一样的(例如,testq %rax,%rax 用来检查 %rax 是负数、零,还是正数),或其中的一个操作数是一个掩码,用来指示哪些位应该被测试。