https://www.hellboundhackers.org/articles/read-article.php?article_id=729
В качестве краткого изложения я написал эту статью для двух целей. Во-первых, это интересно, и всегда полезно больше знать о том, как работает ваш компьютер. Во-вторых, всегда есть программы, в которых с флагами манипулируют напрямую, и полезно знать, какое влияние они окажут на прыжки. Например, что-то простое, как
CMP eax, ebx
Где-то
может запутать большинство начинающих реверсеров, но, надеюсь, не после этой статьи. Наслаждайтесь:)
[Важное примечание: я буду использовать 8-битные целые числа для моих примеров, когда я записываю двоичные числа. Просто помните, что, хотя 8-битные целые числа обычно не используются в программировании, те же самые правила, которые я обсуждаю, применяются к целым числам с большим количеством битов]
Инструкция CMP:
Команда CMP действует путем выполнения подразумеваемого вычитания двух операндов. Это означает, что результат не сохраняется в памяти. Вычитая их, он делает несколько быстрых тестов, обновляя флаги Z, O, C, S и P. Флаг P, или четность, используется редко, поэтому мы будем его игнорировать в целях краткости.
Двоичное вычитание выполняется путем добавления отрицательного варианта второго операнда из первого. Это так же, как то, что вы узнали в средней школе, о том, как 4 + 3 = 4 - (-3), и наоборот.
В конце статьи я объясню, как это делается, но сейчас я перейду к более важным вопросам, поскольку эти знания на самом деле не нужны для взлома или кодирования.
Знак и нулевой флаг:
Четыре флага, которые может установить инструкция CMP - Z, O, C и S, известны как флаги нуля, переполнения, переноса и знака соответственно. Флаг нуля устанавливается всякий раз, когда результат вычитания равен нулю. Это, конечно, происходит только тогда, когда операнды равны. Флаг знака устанавливается, когда результат вычитания отрицательный. Хотя мы склонны думать, что это означает, что флаг знака в сочетании с флагом нуля достаточно для проверки всех>> = <и <=, это не так, поскольку результат может быть отрицательным, даже если первое число больше второй. Это из-за переполнения. </p>
Флаг переполнения:
Целые числа со знаком представляются в двоичном виде с тем же количеством битов, что и целые числа без знака. Это означает, конечно, что знак должен быть установлен в одном из битов целого числа. Знаковые целые числа хранят знак в 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, поэтому перенос не установлен.