Сборка - JG / JNLE / JL / JNGE после CMP - PullRequest
51 голосов
/ 08 марта 2012

Я не понимаю инструкции JG/JNLE/JL/JNGE, которые следуют после CMP.

например, если у меня есть:

CMP al,dl
jg label1

Когда al=101; dl =200.

На что мы спрашиваем jg? Это на al>dl? или al-dl>0?

То же самое по следующему коду:

test al,dl
jg label1

Я не понимаю, что мы сравниваем, и с чем мы спрашиваем "jg".

Другими словами, я не понимаю, когда мы перейдем к label1, а когда - нет.

Ответы [ 4 ]

107 голосов
/ 08 марта 2012

Когда вы делаете 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 в дополнении до двух), первый будет на самом деле больше. Если это не то, что вам нужно, вы должны использовать эквивалентное сравнение без знака.

См. здесь для более подробной информации о выборе прыжков, для полноты воспроизведено ниже. Сначала те, где подпись не подходит:

+--------+------------------------------+-------------+--------------------+
|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    |             |                    |
+--------+------------------------------+-------------+--------------------+
4 голосов
/ 08 марта 2012

Wikibooks имеет довольно хорошее резюме инструкций перехода .По сути, существует два этапа:

cmp_instruction op1, op2

, который устанавливает различные флаги в зависимости от результата, и

jmp_conditional_instruction address

, который выполняет переход на основе результатов этих флагов.*

Сравнение (cmp) в основном вычислит вычитание op1-op2, однако это не сохраняется;вместо этого устанавливаются только результаты флага.Так что, если вы сделали cmp eax, ebx, это то же самое, что сказать eax-ebx, а затем принять решение, основываясь на том, является ли это положительным, отрицательным или нулевым, какие флаги установить.

1 голос

Сложение и вычитание в дополнении к двум одинаковы для чисел со знаком и без знака

Ключевое наблюдение состоит в том, что CMP в основном вычитание и:

В дополнении до двух (целочисленное представление, используемое в x86), сложение со знаком и без знака является одной и той же операцией

Это позволяет, например, разработчикам оборудования реализовать его более эффективно с помощью всего одной схемы.

Так, например, когда вы передаете входные байты инструкции ADD x86, все равно, подписаны они или нет.

Однако ADD устанавливает несколько флагов в зависимости от того, что произошлово время операции:

  • перенос: результат сложения без знака или вычитания не соответствует размеру бита, например: 0xFF + 0x01 или 0x00 - 0x01

    Для сложениянеобходимо перенести 1 на следующий уровень.

  • знак: для результата установлен старший бит.Т.е.: отрицательный, если интерпретируется как подписанный.

  • переполнение: входные верхние биты равны 0 и 0 или 1 и 1, а инвертированный выходной сигнал противоположен.

    Т.е. подписаноперация изменила подпись невозможным способом (например, положительный + положительный или отрицательный

Затем мы можем интерпретировать эти флаги таким образом, чтобы сравнение соответствовало нашим ожиданиям для чисел со знаком или без знака.

Эта интерпретация - именно то, что JA против JG и JB против JL делают для нас!

Пример кода

Вот фрагмент кода GNU GAS, чтобы сделать это болееconcrete:

/* 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 </li>
  • JNA, потому что! (0> 255)
  • JNL, потому что! (0 <-1) </li>
  • JG, потому что 0>-1

Обратите внимание, как в данном конкретном примере имела значение подпись, например, JB, но не JL.

Пример выполнения с утверждениями .

Равные / отрицательные версии, такие как JLE / JNG, являются просто псевдонимами

Рассматривая Руководства разработчика ПО для архитектуры Intel 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).
0 голосов
/ 08 марта 2012

Команда JG просто означает: Прыжок, если больше .Результат предыдущих инструкций хранится в определенных флагах процессора (в этом он будет проверять, если ZF = 0 и SF = OF), и инструкция перехода действует в соответствии с их состоянием.

...