JNZ和CMP汇编指令

32

如果我错了,请纠正我。

这是我对 JNZCMP 的理解。

JNZ - 如果Z标志位不为零(1),则跳转将会发生。

CMP - 如果两个值相等,则设置Z标志位(1),否则不设置(0)。

Olly DBG

这是我正在观看的一个Flash教程。它在教授一个简单的CrackMe的解决方案。

正如你所看到的,上一个指令比较了AL47h。它们相等,这设置了Z标志位(你可以在右侧的寄存器窗口中看到它)。

下一条指令是一个JNZ。我的理解是,如果Z标志被设置,那么跳转会发生。虽然Z标志已经被设置,但跳转却没有发生!

为什么?


1
@nrz,您的评论不是很清楚 - OP是否需要通过非常努力地查看语句来意识到错误? - Michael Foukarakis
@nrz 哎呀,伙计,你是想让我更加困惑吗?!?!从其他答案中,我现在知道使用 JNZ 指令时,只有在零标志位未设置(0)时才会进行跳转。 - 43.52.4D.
2
@43.52.4D。抱歉,我误读了您问题中的句子“JNZ-如果Z标志不为零(1),则跳转将发生”,因此我的评论可能会让人感到困惑,所以我现在已将其删除。Intel x86 JUMP快速参考有一个有用的表格,可用于检查不同x86条件跳转的分支条件。 - nrz
5个回答

47

JNZ是“如果ZF不为零,则跳转(ZF = 0)”的缩写,而不是“如果ZF被设置,则跳转”。

如果更容易记住,可以考虑JNZ和JNE(如果不相等则跳转)是等价的。 因此,在执行cmp al,47并且AL的内容等于47时,ZF被设置,因此不应该进行跳转(如果不相等-JNE)。


31

我会稍微详细地解释一下。

x86中通常有两种条件跳转:

  1. 算术跳转 - 如 JZ(等于跳转)、JC(进位跳转)、JNC(不进位跳转)等。

  2. 比较跳转 - 如 JE(相等跳转)、JB(低于跳转)、JAE(高于或等于跳转)等。

因此,在执行算术或逻辑指令后,只能使用第一种类型的跳转:

sub  eax, ebx
jnz  .result_is_not_zero 

and  ecx, edx
jz   .the_bit_is_not_set

仅在 CMP 指令后使用第二组指令:

cmp  eax, ebx
jne  .eax_is_not_equal_to_ebx

cmp  ecx, edx
ja   .ecx_is_above_than_edx

这样一来,程序会更易读,你也就不会迷惑了。

需要注意的是,有时这些指令实际上是同义词。JZ == JE; JC == JB; JNC == JAE等等。完整的表格如下。正如您所看到的,只有16个条件跳转指令,但有30个助记符-它们提供了更易读的源代码编写方法:

Mnemonic        Condition tested  Description  

jo              OF = 1            overflow 
jno             OF = 0            not overflow 
jc, jb, jnae    CF = 1            carry / below / not above nor equal
jnc, jae, jnb   CF = 0            not carry / above or equal / not below
je, jz          ZF = 1            equal / zero
jne, jnz        ZF = 0            not equal / not zero
jbe, jna        CF or ZF = 1      below or equal / not above
ja, jnbe        CF and ZF = 0      above / not below or equal
js              SF = 1            sign 
jns             SF = 0            not sign 
jp, jpe         PF = 1            parity / parity even 
jnp, jpo        PF = 0            not parity / parity odd 
jl, jnge        SF xor OF = 1     less / not greater nor equal
jge, jnl        SF xor OF = 0     greater or equal / not less
jle, jng    (SF xor OF) or ZF = 1 less or equal / not greater
jg, jnle    (SF xor OF) or ZF = 0 greater / not less nor equal 

对于助记符 ja,jnbe,所测试的条件必须为 CF AND ZF = 0 - Andrew Hardiman
@case_2501:已修复。谢谢。 - johnfound

3

一开始看起来JNZ是指如果不为零则跳转,就像跳转如果零标志为1/设置。

但实际上它表示跳转(如果)不为零(被设置)。

如果0 = 未设置并且1 = 设置,那么只需要记住:
JNZ跳转如果零标志未设置(0)


0
JNZ     Jump if Not Zero    ZF=0

确实,这很令人困惑。

为了更容易理解,将Not Zero替换为Not Set。(请注意,这是为了您自己的理解)

因此,

JNZ     Jump if Not Set     ZF=0

Not Set 表示标志位 Z = 0。所以跳转(如果不设置)

Set 表示标志位 Z = 1。所以,不要跳转


FLAGS 中有多个条件位,其中 ZF 只是其中之一。(其他的有 CF、OF、SF、PF,还有 AF 但不能直接跳转到 AF)。如果你想要明确,可以使用“如果 ZF 未设置则跳转”或者“如果 !ZF 则跳转”。 - Peter Cordes

0

你可以将JNE/Z读作*

Jump if the status is "Not set" on Equal/Zero flag

"Not set"是CPU中的"equal/zero flag"被设置为0时的状态,只有当条件满足或完全匹配时才会发生。


cmp same, same sets ZF, because x - x == 0. jne 的语义意思是当你比较的两个东西不相等时跳转。你回答的最后一句话听起来像是在说当你比较两个相等的东西时,ZF=0,这是错误的。也许你的意思是说“只有在比较完全匹配时才会设置ZF”?但你刚才谈论的是0,然后接着说“...这只发生在”,给那个短语一个隐含的主题ZF=0 - Peter Cordes
请注意,大多数ALU指令都会设置FLAGS标志,因此例如inc eax将在输出EAX值为非零时清除ZF。我不知道这是否符合您所说的“条件已满足”。在jnz之前常用的指令是test eax,eax(或任何其他寄存器);我想你可以称非零EAX为“条件”。无论如何,对于那些不知道FLAGS如何工作的人来说,我认为您的答案并不是很清晰。 - Peter Cordes

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接