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

assembly x86 eflags

116151 观看

4回复

我不理解JG/JNLE/JL/JNGECMP之后的说明。

例如,如果我有:

CMP al,dl
jg label1

al=101; dl =200

我们问jg什么?是al>dl吗?还是al-dl>0

在下一个代码上相同的prolbem:

test al,dl
jg label1

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

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

作者: Adam Sh 的来源 发布者: 2019 年 7 月 9 日

回应 (4)


107

决定

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

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

换句话说,您拥有的第一个代码块(添加了我的注释):

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)进行比较,前者实际上会更大。如果这不是您想要的,那么您应该使用等效的无符号比较。

有关跳转选择的更多详细信息,请参见此处,完整性如下所示。首先是签名不合适的:

+--------+------------------------------+-------------+--------------------+
|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    |             |                    |
+--------+------------------------------+-------------+--------------------+
作者: paxdiablo 发布者: 08.03.2012 12:55

4

Wikibooks对跳转指令有一个相当不错的总结。基本上,实际上有两个阶段:

cmp_instruction op1, op2

根据结果​​设置各种标志,和

jmp_conditional_instruction address

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

Compare(cmp)将基本上计算减法op1-op2,但是,这不存储; 而是仅设置标志结果。所以如果你这样做也是cmp eax, ebx如此eax-ebx- 然后根据是否为正,负或零决定设置标志。

这里有更详细的参考。

作者: user257111 发布者: 08.03.2012 12:55

1

对于有符号和无符号数,二进制补码的加法和减法是相同的

关键的观察是CMP基本上是减法,并且:

二进制补码(x86使用的整数表示)中,有符号和无符号加法是完全相同的操作

这允许例如硬件开发者仅用一个电路就可以更有效地实现它。

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

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

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

    另外,我们需要将1提升到下一个级别。

  • sign:结果有顶部位设置。即:如果被解释为签名则为否定。

  • 溢出:输入顶部位均为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。在英特尔语法中,这将是cmp al, bl

在此之后,将进行以下跳转:

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

注意在这个特定的例子中签名是如何重要的,例如JB被采用但不是JL。

带断言的Runnable示例

JLE / JNG等等/否定版本只是别名

通过查看英特尔64和IA-32架构软件开发人员手册第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).
作者: Ciro Santilli 新疆改造中心996ICU六四事件 发布者: 15.06.2019 08:26

0

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

作者: Lukasz 发布者: 08.03.2012 01:02
32x32