Узнаём условия и циклы в ассемблере

Высокоуровневые конструкции исчезают при компиляции — учимся их узнавать.

Условный переход — инструкция, которая прыгает на другой адрес только если выполнено условие (по результату предыдущего сравнения).

Как условие if превращается в ассемблер

В исходнике:

if (x == 5) {
    // тело
}

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

    cmp  eax, 5      ; сравнить x с 5
    jne  skip        ; если НЕ равно — прыгнуть мимо тела
    ; ... тело if ...
skip:
    ; продолжение

Обратите внимание: компилятор инвертирует условие. Чтобы «войти в if при равенстве», он прыгает мимо при неравенстве (jne).

Таблица условных переходов

ИнструкцияПрыгает, если
je / jzравно / ноль
jne / jnzне равно / не ноль
jl / jgменьше / больше (со знаком)
jb / jaниже / выше (без знака)

Как узнать цикл

Главный признак цикла — переход назад (на меньший адрес). Тело выполняется, в конце условие проверяется, и jmp или условный переход возвращает наверх:

loop_start:
    ; ... тело цикла ...
    inc  ecx          ; счётчик++
    cmp  ecx, 10      ; дошли до 10?
    jl   loop_start   ; нет — назад (это и есть цикл)

Как работает под капотом: флаги

Инструкция cmp a, b вычитает b из a, не сохраняя результат, но выставляет флаги процессора (ноль, знак, перенос). Условные переходы читают эти флаги. Поэтому пара «cmp + условный jump» — это и есть «if» в машинном коде.

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

  • Забывать про инверсию условия компилятором.
  • Не замечать переход назад и пропускать цикл.
  • Путать переходы со знаком (jl/jg) и без знака (jb/ja).

Итог

  • if = cmp + условный переход (часто с инверсией условия).
  • Цикл узнаётся по переходу назад.
  • Переходы опираются на флаги, выставленные cmp.
Проверьте себя
1. По какому признаку в ассемблере проще всего узнать цикл?
AПо инструкции mov
BПо переходу (jump) назад, на меньший адрес
CПо отсутствию инструкции ret
DПо наличию строк
2. Что делает инструкция cmp eax, 5?
AКладёт 5 в eax
BСравнивает eax с 5, выставляя флаги (не сохраняя результат)
CПрибавляет 5 к eax
DПереходит на адрес 5