Сборка - JG/JNLE/JL/JNGE после CMP
Я не понимаю 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, а когда - нет.
Благодарю.
3 ответа
Когда вы делаете 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 | | |
+--------+------------------------------+-------------+--------------------+
В Wikibooks есть довольно хорошая сводка инструкций по прыжкам. По сути, есть две стадии:
cmp_instruction op1, op2
Который устанавливает различные флаги на основе результата, и
jmp_conditional_instruction address
который выполнит переход на основе результатов этих флагов.
Сравнить (cmp
) будет в основном вычислять вычитание op1-op2
Однако это не сохраняется; вместо этого устанавливаются только результаты флага. Так что если вы сделали cmp eax, ebx
это то же самое, что сказать eax-ebx
- затем принимается решение на основе положительного, отрицательного или нулевого значения, какие флаги устанавливать.
Более подробная ссылка здесь.
Сложение и вычитание в двух дополнениях одинаковы для чисел со знаком и без знака.
Ключевое наблюдение состоит в том, что CMP - это в основном вычитание, и:
В дополнении до двух (целочисленное представление, используемое 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.
Работоспособный пример с утверждениями.
Равные / отрицательные версии, такие как JLE / JNG, являются просто псевдонимами
Посмотрев на раздел "Jcc - Перейти, если условие выполнено " Руководства разработчика программного обеспечения для архитектур Intel 64 и IA-32, том 2, мы видим, что кодировки идентичны, например:
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).
Команда JG просто означает: перейти, если больше. Результат предыдущих инструкций сохраняется в определенных флагах процессора (в этом он будет проверять, если ZF=0 и SF=OF), и инструкция перехода действует в соответствии с их состоянием.