x86 汇编 · 有符号比较

JGE 五种情况逐一详解

CMP A, B 之后,SF 和 OF 的每一种组合为什么能正确判断 A ≥ B
所有计算均使用 CPU 真实执行方式:A + (~B) + 1

01  /  总览表

五种情况一览

以 8 位有符号数为例(范围 −128 ~ +127),CMP A, B 即 A − B,CPU 内部执行 A + (~B) + 1:

情况 A − B 结果 SF OF SF = OF? 跳转?
① A > B,无溢出 正数 0 0 0 = 0 ✔ 跳转
② A = B,无溢出 0 0 0 = 0 ✔ 跳转
③ A < B,无溢出 负数 1 0 1 ≠ 0 ✘ 不跳
④ A < B,有溢出 符号被翻转 0 1 0 ≠ 1 ✘ 不跳
⑤ A > B,有溢出 符号被翻转 1 1 1 = 1 ✔ 跳转
02  /  逐一详解

每种情况的具体推导(全部使用补码加法)

1
A > B,无溢出
SF=0 OF=0 → 跳转 ✔

例子:A = 50,B = 20,真实结果 50 − 20 = 30,在 −128~+127 范围内,无溢出。

CPU 执行:A + (~B) + 1 A = 50 → 0011 0010 B = 20 → 0001 0100 ~B → 1110 1011 0011 0010 (A) + 1110 1011 (~B) + 1 (+1) ─────────── 1 0001 1110 Carry_Out = 1(溢出到第8位) 寄存器结果:0001 1110 = 30(正数) Carry_In(bit7) = 1(bit6 向 bit7 的进位) Carry_Out(bit7) = 1(bit7 向更高位的进位) OF = 1 XOR 1 = 0(无溢出)
SF 0
OF 0
SF=OF? 0=0 ✔

分析:结果 30 是正数,最高位为 0,所以 SF=0。Carry_In 和 Carry_Out 都是 1,进位"穿过"了 bit7,符号位未被篡改,OF=0。SF 如实反映了"结果为正",不需要任何纠正。SF=OF=0,XOR 结果为 0,说明 A−B ≥ 0,即 A ≥ B,JGE 跳转,正确。

这是最简单的情况:没有溢出,SF 可信,SF=0 直接说明结果是正数,A > B。
2
A = B,无溢出
SF=0 OF=0 → 跳转 ✔

例子:A = 30,B = 30,真实结果 30 − 30 = 0,无溢出。

CPU 执行:A + (~B) + 1 A = 30 → 0001 1110 B = 30 → 0001 1110 ~B → 1110 0001 0001 1110 (A) + 1110 0001 (~B) + 1 (+1) ─────────── 1 0000 0000 Carry_Out = 1(溢出到第8位) 寄存器结果:0000 0000 = 0 Carry_In(bit7) = 1(bit6 向 bit7 的进位) Carry_Out(bit7) = 1(bit7 向更高位的进位) OF = 1 XOR 1 = 0(无溢出)
SF 0
OF 0
ZF 1
SF=OF? 0=0 ✔

分析:结果为 0,最高位为 0,SF=0。Carry_In 和 Carry_Out 都是 1,进位穿过了 bit7,OF=0。零既不是正数也不是负数,但在 JGE(大于等于)的语义中,等于也应该跳转。SF=OF=0 满足条件,跳转,正确。

注意:此时 ZF=1(结果为零)。实际上 JGE 只看 SF=OF,不看 ZF。等于的情况恰好也满足 SF=OF,所以"大于"和"等于"被同一个条件统一了。如果想单独判断"大于"(不含等于),用 JG,它额外要求 ZF=0。
3
A < B,无溢出
SF=1 OF=0 → 不跳 ✘

例子:A = 20,B = 50,真实结果 20 − 50 = −30,在 −128~+127 范围内,无溢出。

CPU 执行:A + (~B) + 1 A = 20 → 0001 0100 B = 50 → 0011 0010 ~B → 1100 1101 0001 0100 (A) + 1100 1101 (~B) + 1 (+1) ─────────── 0 1110 0010 Carry_Out = 0(没有溢出到第8位) 寄存器结果:1110 0010 = −30(补码) Carry_In(bit7) = 0(bit6 没有向 bit7 进位) Carry_Out(bit7) = 0(bit7 没有向更高位进位) OF = 0 XOR 0 = 0(无溢出)
SF 1
OF 0
SF=OF? 1≠0 ✘

分析:结果 −30 是负数,最高位为 1,SF=1。Carry_In 和 Carry_Out 都是 0,进出一致,符号位未被篡改,OF=0。SF 如实反映了"结果为负",不需要纠正。SF≠OF,XOR 结果为 1,说明 A−B < 0,即 A < B,JGE 不跳,正确。

同样简单:没有溢出,SF 可信,SF=1 直接说明结果是负数,A < B,不应该跳转。
4
A < B,有溢出(负溢出)
SF=0 OF=1 → 不跳 ✘

例子:A = −100,B = 80,真实结果 −100 − 80 = −180,超出 −128 的下限,发生负溢出。

CPU 执行:A + (~B) + 1 A = −100 → 1001 1100(补码) B = 80 → 0101 0000 ~B → 1010 1111 1001 1100 (A) + 1010 1111 (~B) + 1 (+1) ─────────── 1 0100 1100 Carry_Out = 1(溢出到第8位) 寄存器结果:0100 1100 = +76(有符号解读) 真实结果应该是 −180,但寄存器里却是 +76 负数变成了正数!符号被翻转了。 逐位追踪进位: bit0: 0+1+1=10 carry=1 bit1: 0+1+1=10 carry=1 bit2: 1+1+1=11 carry=1 bit3: 1+1+1=11 carry=1 bit4: 1+0+1=10 carry=1 bit5: 0+1+1=10 carry=1 bit6: 0+0+1=01 carry=0 ← Carry_In(bit7) = 0 bit7: 1+1+0=10 carry=1 ← Carry_Out(bit7) = 1 OF = Carry_In XOR Carry_Out = 0 XOR 1 = 1(溢出!)
SF 0
OF 1
SF=OF? 0≠1 ✘

分析:结果的最高位是 0,所以 SF=0,看起来是正数。但这是假象——真实结果 −180 是负数,只是被截断后符号翻转了。Carry_In=0 但 Carry_Out=1,进出不一致,说明进位在 bit7 处"凭空产生",篡改了符号位,OF=1。

推理过程:

SF 说:结果是正数(SF=0) ← 假象 OF 说:发生了溢出(OF=1) ← SF 的符号被翻转了 真实符号 = SF XOR OF = 0 XOR 1 = 1 → 负数 真实结果是负数 → A − B < 0 → A < B → 不应跳转 SF ≠ OF → JGE 不跳 → 正确 ✔
关键理解:SF=0 让你以为 A ≥ B,但 OF=1 打了一个"警告标签"——SF 在说谎。SF≠OF,两者不一致,恰好意味着"SF 的判断要反过来",真实结果其实是负数。
5
A > B,有溢出(正溢出)
SF=1 OF=1 → 跳转 ✔

例子:A = 100,B = −50,真实结果 100 − (−50) = 150,超出 +127 的上限,发生正溢出。

CPU 执行:A + (~B) + 1 A = 100 → 0110 0100 B = −50 → 1100 1110(补码) ~B → 0011 0001 0110 0100 (A) + 0011 0001 (~B) + 1 (+1) ─────────── 0 1001 0110 Carry_Out = 0(没有溢出到第8位) 寄存器结果:1001 0110 = −106(有符号解读) 真实结果应该是 +150,但寄存器里却是 −106 正数变成了负数!符号被翻转了。 逐位追踪进位: bit0: 0+1+1=10 carry=1 bit1: 0+0+1=01 carry=0 bit2: 1+0+0=01 carry=0 bit3: 0+0+0=00 carry=0 bit4: 0+1+0=01 carry=0 bit5: 1+1+0=10 carry=1 bit6: 1+0+1=10 carry=1 ← Carry_In(bit7) = 1 bit7: 0+0+1=01 carry=0 ← Carry_Out(bit7) = 0 OF = Carry_In XOR Carry_Out = 1 XOR 0 = 1(溢出!)
SF 1
OF 1
SF=OF? 1=1 ✔

分析:结果的最高位是 1,所以 SF=1,看起来是负数。但这又是假象——真实结果 +150 是正数,只是超过了 +127 被截断后符号翻转了。Carry_In=1 但 Carry_Out=0,进出不一致,说明低位进位"被困在"了 bit7 里,篡改了符号位,OF=1。

推理过程:

SF 说:结果是负数(SF=1) ← 假象 OF 说:发生了溢出(OF=1) ← SF 的符号被翻转了 真实符号 = SF XOR OF = 1 XOR 1 = 0 → 正数 真实结果是正数 → A − B > 0 → A > B → 应该跳转 SF = OF → JGE 跳转 → 正确 ✔
关键理解:SF=1 让你以为 A < B,但 OF=1 告诉你"SF 在说谎,要取反"。SF=OF=1,两个 1 异或得 0,说明真实结果是正数。虽然 SF 和 OF 都是 1,看起来"双重异常",但两个异常恰好抵消——就像"负负得正"。
03  /  统一理解

用一个公式统一五种情况

真实符号
= SF ⊕ OF
OF=0 时:真实符号 = SF(SF 可信)
OF=1 时:真实符号 = NOT(SF)(SF 说谎,取反)
OF SF 真实符号 = SF⊕OF 含义 JGE 跳转?
0(SF 可信) 0 0 → 正/零 A ≥ B 跳转(①②)
0(SF 可信) 1 1 → 负 A < B 不跳(③)
1(SF 说谎) 0 1 → 负(取反) A < B 不跳(④)
1(SF 说谎) 1 0 → 正(取反) A > B 跳转(⑤)
为什么溢出只发生在情况 ④⑤:溢出只在"真实结果超出 8 位有符号范围"时才会发生。情况 ①②③ 的真实结果都在 −128~+127 之间,根本不会溢出,所以 OF 一定是 0。只有当 A 和 B 的符号不同且差值很大时(比如大正数减大负数,或大负数减大正数),结果才会超出范围,OF 才会被置为 1。
总结

SF 是"加了噪声的符号",OF 是噪声本身。

OF=0 时,没有噪声,SF 可以直接信任。

OF=1 时,噪声存在,SF 的含义被翻转了,需要取反才能还原真实符号。

SF XOR OF 一步完成了去噪:结果为 0 表示真实结果非负(A ≥ B),结果为 1 表示真实结果为负(A < B)。

JGE 的条件 SF=OF 等价于 SF XOR OF = 0,即真实结果 ≥ 0,即 A ≥ B。五种情况全部正确。