CMP, JMP, JE, JNZ: условия и циклы в ассемблере

В C++ условие выглядит привычно:.

Ниже — разделы про cMP: сравнить, jE: перейти, если равно и jMP: безусловный переход, чтобы быстро понять устройство материала, практические ограничения и типовые точки отказа.


В C++ условие выглядит привычно:

if (value == 10) {
    result = 1;
} else {
    result = 0;
}

В ассемблере нет такого красивого if. Есть сравнение, флаги и переходы. Именно здесь появляются CMP, JMP, JE, JNZ

CMP: сравнить

cmp ax, 10

cmp сравнивает ax с 10 и выставляет флаги. Сам ax не меняется

Если ax равен 10, будет выставлен флаг нуля, и переход je сможет сработать

JE: перейти, если равно

mov ax, 10
cmp ax, 10
je equal_label

Если значения равны, выполнение перейдет на метку equal_label

Метка:

equal_label:

Метка — это имя места в коде

JMP: безусловный переход

jmp end

jmp переходит всегда. Он не проверяет флаги

В условной конструкции он нужен, чтобы перепрыгнуть блок else

if/else на ассемблере

mov ax, 10
cmp ax, 10
je equal_label

mov bx, 0
jmp end

equal_label:
mov bx, 1

end:

Логика:

  • если ax == 10, перейти к equal_label;
  • иначе положить 0 в bx;
  • после equal_label положить 1 в bx.

Это похоже на:

if (ax == 10) {
    bx = 1;
} else {
    bx = 0;
}

JNZ: перейти, если не ноль

jnz означает jump if not zero

После cmp его часто используют как "перейти, если не равно":

cmp ax, 10
jnz not_equal

Если результат сравнения не ноль, значения разные

jne и jnz во многих x86-контекстах являются близкими по смыслу для такой проверки

Цикл через JNZ

Сделаем счетчик от 3 до 1:

mov cx, 3

loop_start:
sub cx, 1
cmp cx, 0
jnz loop_start

Что происходит:

  1. В cx кладем 3.
  2. Вычитаем 1.
  3. Сравниваем с 0.
  4. Если не ноль, возвращаемся к началу.

Проходы:

cx = 3 -> sub -> 2 -> не ноль
cx = 2 -> sub -> 1 -> не ноль
cx = 1 -> sub -> 0 -> выход

Почему порядок команд важен

Так правильно:

cmp cx, 0
jnz loop_start

Если между cmp и jnz вставить команду, которая меняет флаги, переход будет смотреть уже не на то сравнение

Например:

cmp cx, 0
add ax, 1
jnz loop_start

add может изменить флаги. Это уже опасная логика

CMP против TEST

test часто используют для проверки нуля:

test ax, ax
jnz not_zero

Но для первого урока достаточно cmp:

cmp ax, 0
jnz not_zero

test можно добавить позже

Частые ошибки

Метка написана с опечаткой

je equl_label

А ниже:

equal_label:

Assembler не найдет метку

Забыли jmp после else-блока

Если не перепрыгнуть equal_label, может выполниться оба блока

Думают, что cmp меняет значение

Не меняет. Он меняет флаги

Вставили флаг-меняющую команду перед переходом

Переход смотрит на последние актуальные флаги

Мини-задания

  1. Проверь, равно ли ax числу 5.
  2. Если равно, положи в bx 100.
  3. Если не равно, положи в bx 0.
  4. Сделай цикл, который уменьшает cx от 5 до 0.
  5. Попробуй заменить jnz на je и объяснить, что изменилось.

Ответы на эти вопросы могут быть для вас полезными

Что делает CMP?

Сравнивает значения и выставляет флаги, но не сохраняет результат вычитания

Чем JMP отличается от JE?

JMP переходит всегда. JE переходит только если предыдущее сравнение показало равенство

Что значит JNZ?

Jump if not zero — перейти, если результат не ноль

Как сделать цикл в ассемблере?

Через метку, изменение счетчика, сравнение и условный переход назад

Почему код после CMP ведет себя странно?

Возможно, между cmp и переходом есть команда, которая изменила флаги

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

Если вы собираете тему по шагам, рядом лучше открыть:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x