装配 - CMP后的JG / JNLE / JL / JNGE

时间:2012-03-08 12:46:26

标签: assembly x86

我不理解CMP之后的JG/JNLE/JL/JNGE指令。

例如,如果我有:

CMP al,dl
jg label1

al=101; dl =200

关于我们问jg的问题?是al>dl吗?还是al-dl>0

下一个代码相同的增量:

test al,dl
jg label1

我不明白我们比较什么,以及我们问“jg”。

换句话说,我不明白我们何时会跳转到label1,何时不会跳转。

感谢。

4 个答案:

答案 0 :(得分:105)

当您执行cmp a,b时,标记设置就像您计算了a - b一样。

然后jmp - 类型指令检查那些标志以查看是否应该进行跳转。

换句话说,你拥有的第一个代码块(添加了我的评论):

cmp al,dl     ; set flags based on the comparison
jg label1     ; then jump based on the flags
当且仅当label1大于al时,

才会跳转至dl

你最好把它当作al > dl来考虑,但你在那里的两个选择在数学上是等价的:

al > dl
al - dl > dl - dl (subtract dl from both sides)
al - dl > 0       (cancel the terms on the right hand side)

使用jg时需要小心,因为它假设您的值已签名。因此,如果将字节 101(二进制补码中的101)与200(二进制中的-56)进行比较,前者实际上会更大。如果那不是你想要的,你应该使用等效的无符号比较。

有关跳跃选择的详细信息,请参阅here,完整性如下所示。首先是签名不合适的人:

+--------+------------------------------+-------------+--------------------+
|Instr   | Description                  | signed-ness | Flags              |
+--------+------------------------------+-------------+--------------------+
| JO     | Jump if overflow             |             | OF = 1             |
+--------+------------------------------+-------------+--------------------+
| JNO    | Jump if not overflow         |             | OF = 0             |
+--------+------------------------------+-------------+--------------------+
| JS     | Jump if sign                 |             | SF = 1             |
+--------+------------------------------+-------------+--------------------+
| JNS    | Jump if not sign             |             | SF = 0             |
+--------+------------------------------+-------------+--------------------+
| JE/    | Jump if equal                |             | ZF = 1             |
| JZ     | Jump if zero                 |             |                    |
+--------+------------------------------+-------------+--------------------+
| JNE/   | Jump if not equal            |             | ZF = 0             |
| JNZ    | Jump if not zero             |             |                    |
+--------+------------------------------+-------------+--------------------+
| JP/    | Jump if parity               |             | PF = 1             |
| JPE    | Jump if parity even          |             |                    |
+--------+------------------------------+-------------+--------------------+
| JNP/   | Jump if no parity            |             | PF = 0             |
| JPO    | Jump if parity odd           |             |                    |
+--------+------------------------------+-------------+--------------------+
| JCXZ/  | Jump if CX is zero           |             | CX = 0             |
| JECXZ  | Jump if ECX is zero          |             | ECX = 0            |
+--------+------------------------------+-------------+--------------------+

然后是未签名的:

+--------+------------------------------+-------------+--------------------+
|Instr   | Description                  | signed-ness | Flags              |
+--------+------------------------------+-------------+--------------------+
| JB/    | Jump if below                | unsigned    | CF = 1             |
| JNAE/  | Jump if not above or equal   |             |                    |
| JC     | Jump if carry                |             |                    |
+--------+------------------------------+-------------+--------------------+
| JNB/   | Jump if not below            | unsigned    | CF = 0             |
| JAE/   | Jump if above or equal       |             |                    |
| JNC    | Jump if not carry            |             |                    |
+--------+------------------------------+-------------+--------------------+
| JBE/   | Jump if below or equal       | unsigned    | CF = 1 or ZF = 1   |
| JNA    | Jump if not above            |             |                    |
+--------+------------------------------+-------------+--------------------+
| JA/    | Jump if above                | unsigned    | CF = 0 and ZF = 0  |
| JNBE   | Jump if not below or equal   |             |                    |
+--------+------------------------------+-------------+--------------------+

最后,签名的那些:

+--------+------------------------------+-------------+--------------------+
|Instr   | Description                  | signed-ness | Flags              |
+--------+------------------------------+-------------+--------------------+
| JL/    | Jump if less                 | signed      | SF <> OF           |
| JNGE   | Jump if not greater or equal |             |                    |
+--------+------------------------------+-------------+--------------------+
| JGE/   | Jump if greater or equal     | signed      | SF = OF            |
| JNL    | Jump if not less             |             |                    |
+--------+------------------------------+-------------+--------------------+
| JLE/   | Jump if less or equal        | signed      | ZF = 1 or SF <> OF |
| JNG    | Jump if not greater          |             |                    |
+--------+------------------------------+-------------+--------------------+
| JG/    | Jump if greater              | signed      | ZF = 0 and SF = OF |
| JNLE   | Jump if not less or equal    |             |                    |
+--------+------------------------------+-------------+--------------------+

答案 1 :(得分:4)

Wikibooks对jump instructions有一个相当不错的总结。基本上,实际上有两个阶段:

cmp_instruction op1, op2

根据结果设置各种标志,

jmp_conditional_instruction address

将根据这些标志的结果执行跳转。

比较(cmp)将基本上计算减法op1-op2,但是,这不存储;而是仅设置标志结果。因此,如果你cmp eax, ebxeax-ebx相同,那么根据是否为正,负或零决定要设置的标志。

更详细的参考here

答案 2 :(得分:1)

有符号和无符号数字的补码加法和减法相同

主要观察结果是CMP基本上是减法,并且:

  

two's complement(x86使用的整数表示形式)中,有符号和无符号加法是完全相同的操作

例如,这允许硬件开发人员仅用一个电路就能更有效地实现它。

例如,当您将输入字节提供给x86 ADD指令时,它并不关心它们是否已签名。

但是,ADD会根据操作期间发生的情况设置一些标志:

  • 进位:无符号加法或减法结果不适合位大小,例如:0xFF + 0x01或0x00-0x01

    另外,我们需要将1升至下一个水平。

  • 符号:结果设置了最高位。即:如果解释为带符号,则为负。

  • 溢出:输入高位都是0和0或1和1,而输出反转是相反的。

    即签名操作以一种不可能的方式改变了隔离度(例如,肯定+肯定或否定

然后我们可以以一种使比较符合我们对有符号或无符号数字的期望的方式解释这些标志。

这种解释正是JA vs JG和JB vs JL为我们所做的!

代码示例

以下是GNU GAS的代码片段,以使其更加具体:

/* 0x0 ==
 *
 * * 0 in 2's complement signed
 * * 0 in 2's complement unsigned
 */
mov $0, %al

/* 0xFF ==
 *
 * *  -1 in 2's complement signed
 * * 255 in 2's complement unsigned
 */
mov $0xFF, %bl

/* Do the operation "Is al < bl?" */
cmp %bl, %al

请注意,AT&T语法为“向后”:mov src, dst。因此,您必须在头脑中颠倒操作数,以使条件代码对cmp有意义。在Intel语法中,该值为cmp al, bl

此后,将进行以下跳转:

  • JB,因为0 <255
  • JNA,因为!(0> 255)
  • JNL,因为!(0 <-1)
  • JG,因为0> -1

请注意,在此特定示例中,签名的重要性如何,例如JB被录取,但JL不被录取。

Runnable example with assertions

等于/否定版本(例如JLE / JNG)只是别名

通过查看Intel 64 and IA-32 Architectures Software Developer's Manuals Volume 2部分“ Jcc-满足条件时跳转”,我们看到编码是相同的,例如:

Opcode  Instruction  Description
7E cb   JLE rel8     Jump short if less or equal (ZF=1 or SF ≠ OF).
7E cb   JNG rel8     Jump short if not greater (ZF=1 or SF ≠ OF).

答案 3 :(得分:0)

命令JG只是意味着:如果更大则跳转。前面指令的结果存储在某些处理器标志中(在此将测试ZF = 0和SF = OF),并且跳转指令根据其状态进行操作。