Ассемблер

CMP в ассемблере: как работает сравнение

CMP в ассемблере нужен для сравнения значений перед условным переходом. Он сам никуда не прыгает и не записывает ответ «больше» или «меньше» в отдельную переменную. Он выставляет флаги процессора, а следующая команда перехода решает, что делать дальше

Типичная пара выглядит так:

cmp eax, 100
jl small_value

Смысл: сравнить eax со 100; если eax меньше 100, перейти на метку small_value

Как читать строку cmp

В Intel/NASM-синтаксисе:

cmp eax, 100

читается как:

сравнить eax со 100

Для понимания флагов можно представлять это как:

eax - 100

Но результат не сохраняется. Если в eax было 90, там и останется 90

Пример if на ассемблере

Допустим, нужно сделать аналог:

if (x == 10) {
    y = 1;
} else {
    y = 0;
}

На ассемблере:

cmp eax, 10
je equal

mov ebx, 0
jmp done

equal:
    mov ebx, 1

done:

Здесь eax хранит x, а ebx получает результат. Если eax == 10, переход идет к equal. Если нет, выполняется ветка с mov ebx, 0

Таблица базовых переходов

После cmp a, b удобно читать переходы так:

Переход Смысл
je или jz равно
jne или jnz не равно
jl меньше для signed
jle меньше или равно для signed
jg больше для signed
jge больше или равно для signed
jb меньше для unsigned
jbe меньше или равно для unsigned
ja больше для unsigned
jae больше или равно для unsigned

Главная ошибка — использовать signed-переход для беззнаковых чисел или наоборот

Signed и unsigned на примере

Возьмем байт:

mov al, 0FFh
cmp al, 1

Если считать al как signed, 0FFh можно воспринимать как -1. Тогда -1 < 1

Если считать al как unsigned, 0FFh — это 255. Тогда 255 > 1

Именно поэтому существуют разные переходы. jl и jg подходят для знаковых сравнений, а jb и ja — для беззнаковых

Проверка нуля

Для проверки нуля часто пишут:

cmp eax, 0
je zero_value
jne not_zero

Это понятный вариант для новичка. Позже вы встретите:

test eax, eax
je zero_value

test тоже выставляет флаги, но работает через побитовое И. Для первого знакомства с условиями cmp проще

Как использовать CMP в цикле

mov ecx, 0

again:
    add ecx, 1
    cmp ecx, 5
    jl again

Цикл повторяется, пока ecx < 5. После сравнения переход jl смотрит на флаги и решает, возвращаться к метке или идти дальше

Что проверить при ошибке

Если условие срабатывает не так:

  • посмотрите, какой регистр реально сравнивается;
  • убедитесь, что порядок операндов правильный;
  • проверьте, signed это сравнение или unsigned;
  • убедитесь, что между cmp и переходом нет команды, которая меняет флаги;
  • проверьте размер операндов: байт, слово, двойное слово или 64-битное значение.

Что почитать дальше по ассемблеру

Если нужен общий маршрут по теме, откройте рубрику ассемблеру. Для соседних задач пригодятся эти разборы:

Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные

Настройки cookie

0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x