Узнаём условия и циклы в ассемблере
Высокоуровневые конструкции исчезают при компиляции — учимся их узнавать.
Условный переход — инструкция, которая прыгает на другой адрес только если выполнено условие (по результату предыдущего сравнения).
Как условие 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