Почему CMP (сравнивать) иногда устанавливает флаг переноса в сборке 8086?

Я читал вокруг и с набором инструкций 8086, он говорит, что CMP (сравнить) может установить флаг переноса. Я понимаю, что сравнение вычитает два операнда, но мне было интересно, если кто-нибудь может привести пример, когда это так.

Я просто не могу понять идею добавления числа, и отрицательное число установит флаг переноса. Я прочитал флаг заимствования, но мне просто нужен пример, чтобы уточнить мое понимание инструкции сравнения.

Кроме того, я понимаю, что если 3 - 5 = -2 будет устанавливать отрицательный флаг... когда устанавливается перенос?

4 ответа

  • Флаг переноса устанавливается после операции, которая привела к недостаточному или переполнению. Например, вычитание 10 из 6 приведет к недостаточному переполнению и установит флаг переноса. Точно так же добавление 1 к максимальному значению регистра приведет к переполнению и установит флаг переноса.
  • Флаг переноса также изменяется во время операции сдвига, для него устанавливается значение последнего бита, сдвинутого из регистра назначения.
  • Битовое тестирование помещает значение проверенного бита в флаг переноса. Операционные коды, которые делают это: BT, BTC, BTR и BTS.
  • Инструкции, которые напрямую влияют на флаг переноса: CLC, CMC и STC.
  • Во время сравнения флаг переноса устанавливается так, как если бы два операнда были вычтены.
  • Во время отрицания (NEG) флаг переноса устанавливается, если операнд не равен нулю, и в этом случае он очищается.

Флаг переноса обычно устанавливается при использовании беззнаковой арифметики. Например, добавление двух чисел без знака (результат которых не помещается в регистр) не будет поднимать флаг переполнения, а только будет содержать флаг переноса. Однако при использовании знаковой арифметики в таком событии устанавливается флаг переполнения.

Вы можете найти примеры, когда флаги переноса и переполнения установлены в 0 и 1 после сложения или вычитания целых чисел в этом ответе на связанный вопрос.
Вы также можете найти там пример кода C, эмулирующего сложение с переносом и вычитание с инструкциями заимствования для 8-битных чисел, и вы можете поиграть с этим, может быть, получите больше примеров.

Формат вывода там примерно такой:
127( 127) - 255( -1) - 1 = 127( 127) CY=1 OV=0
Где каждое число представлено как подписанное без знака и заключенное в скобки со знаком (дополнение 2) рядом с ним. Число перед = флаг переноса перед АЦП / СББ. CY= а также OV= показать флаги переноса и переполнения после ADC/SBB.

Сравнение делает почти то же самое, что и вычитание без заимствования, за исключением того, что оно влияет только на флаги переноса, переполнения, знака и нуля (а также четности и вспомогательного переноса, но они здесь не важны) без изменения какого-либо числа в регистре / памяти.

https://www.hellboundhackers.org/articles/read-article.php?article_id=729

В качестве краткого резюме я написал эту статью для двух целей. Во-первых, это интересно, и всегда полезно больше знать о том, как работает ваш компьютер. Во-вторых, всегда есть программы, в которых с флагами манипулируют напрямую, и полезно знать, какое влияние они окажут на прыжки. Например, что-то простое, например CMP eax,ebx JC где-то может запутать большинство начинающих реверсеров, но, надеюсь, не после этой статьи. Наслаждаться:)

[Важное примечание: я буду использовать 8-битные целые числа для моих примеров, когда я записываю двоичные числа. Просто помните, что, хотя 8-битные целые числа обычно не используются в программировании, те же самые правила, которые я обсуждаю, применяются к целым числам с большим количеством битов]

Инструкция CMP:

Инструкция CMP работает путем выполнения подразумеваемого вычитания двух операндов. Это означает, что результат не сохраняется в памяти. Вычитая их, он делает несколько быстрых тестов, обновляя флаги Z,O,C,S и P. Флаг P, или четность, используется редко, поэтому мы будем его игнорировать в целях краткости.

Двоичное вычитание выполняется путем добавления отрицательного варианта второго операнда из первого. Это так же, как то, что вы узнали в средней школе, о том, как 4+3 = 4 - (-3), и наоборот. В конце статьи я объясню, как это делается, но сейчас я перейду к более важным вопросам, поскольку эти знания на самом деле не нужны для взлома или кодирования.

Знак и нулевой флаг:

Четыре флага, которые может установить инструкция CMP - Z,O,C и S, известны как флаги нуля, переполнения, переноса и знака соответственно. Флаг нуля устанавливается всякий раз, когда результат вычитания равен нулю. Это, конечно, происходит только тогда, когда операнды равны. Флаг знака устанавливается, когда результат вычитания отрицательный. Хотя мы склонны думать, что это означает, что флаг знака в сочетании с флагом нуля достаточно для проверки всех> >= <и <=, это не так, поскольку результат может быть отрицательным, даже если первое число больше второй. Это из-за переполнения.

Флаг переполнения:

Целые числа со знаком представляются в двоичном виде с тем же количеством битов, что и целые числа без знака. Это, конечно, означает, что знак должен быть установлен в одном из битов целого числа. Знаковые целые числа хранят знак в MSB (самый значащий бит). Это означает, что, в то время как 00000001 преобразуется в 1 в десятичном виде, 10000001 преобразуется в -127. Я буду обсуждать, почему это -127, а не -1 или -2 позже в этой статье. Когда процессор выполняет вычитание, он оборачивается, если вычитание опускается ниже 00000000 или выше 11111111. Поэтому, если вы вычтите отрицательное число из положительного или вычтите положительное число из отрицательного, есть вероятность, что ответ будет переполнение через границу. Например, 100 - (-100) равно 200, но самое высокое значение 8-разрядного целого числа со знаком может быть 127, поэтому 200 будет проходить через верхнюю границу и получится как отрицательное число, даже если оно должно быть положительным, Та же проблема возникает с -100 - 100; Он проходит через нижний предел и в конечном итоге оказывается положительным, когда должен быть отрицательным, вызывая недостаточный поток. Обратите внимание, что при переполнении также устанавливается флаг переполнения, и переполнение будет ссылаться как на переполнение, так и на переполнение в дальнейшем в статье. CPU проверяет это и устанавливает флаг переполнения, если это происходит.

Нести флаг:

Флаг переноса устанавливается, когда, если оба операнда интерпретируются как целые числа без знака, первый из них больше. Это легко определить, потому что это происходит всякий раз, когда вычитание проходит через 00000000 в верхний диапазон (11111111). Например, 00000001 - 00000010 = 11111111, поэтому перенос установлен. Однако 00000010 - 00000001 = 00000001, поэтому перенос не установлен.

Другие вопросы по тегам