Ассемблер

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

Цикл в ассемблере делают через метку, изменение счетчика и переход. В языках высокого уровня вы пишете for или while, а в ассемблере явно указываете: где начало цикла, что меняется на каждом шаге, когда остановиться и куда перейти дальше

Простая схема цикла

Любой базовый цикл можно представить так:

счетчик = 0
начало:
  сделать работу
  увеличить счетчик
  сравнить счетчик с пределом
  если еще не конец - перейти в начало

В ассемблере эту схему выражают через регистр, метку, cmp и условный переход

Пример цикла на x86 в NASM-стиле

mov ecx, 0          ; счетчик = 0

loop_start:
    ; здесь была бы полезная работа
    add ecx, 1      ; счетчик++
    cmp ecx, 5      ; сравнить ecx и 5
    jl loop_start   ; если ecx < 5, повторить

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

  • ecx хранит счетчик;
  • loop_start — метка, куда можно прыгнуть;
  • add ecx, 1 увеличивает счетчик;
  • cmp ecx, 5 выставляет флаги по результату сравнения;
  • jl loop_start делает переход, если счетчик меньше 5.

Такой цикл выполнит тело пять раз: для значений 0, 1, 2, 3, 4

Вариант с убывающим счетчиком

Иногда удобнее считать вниз:

mov ecx, 5

again:
    ; полезная работа
    sub ecx, 1
    cmp ecx, 0
    jne again

Здесь цикл повторяется, пока ecx не станет равен нулю. Инструкция jne означает «jump if not equal» — перейти, если сравнение не показало равенство

Почему важно понимать флаги

cmp не сохраняет результат вычитания в регистр. Он сравнивает значения и выставляет флаги процессора. Условный переход смотрит именно на флаги. Поэтому между cmp и переходом не стоит вставлять инструкцию, которая меняет флаги, если вы не понимаете последствий

Например:

cmp ecx, 5
add eax, 1
jl loop_start

Такой код может работать не так, как ожидается, потому что add тоже меняет флаги

Цикл и инструкция loop

В x86 есть инструкция loop, которая уменьшает ecx и переходит, пока счетчик не ноль:

mov ecx, 5

again:
    ; работа
    loop again

Для обучения она полезна, но в реальном современном коде чаще используют явные dec/cmp/jcc или другие конструкции, потому что они понятнее и лучше контролируются

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

Не меняют счетчик

Если счетчик не увеличивается или не уменьшается, цикл станет бесконечным

Сравнивают не тот регистр

Проверьте, что cmp использует именно тот регистр, который меняется внутри цикла

Ломают флаги между cmp и переходом

Не вставляйте арифметические инструкции между сравнением и условным переходом без необходимости

Путают signed и unsigned переходы

jl подходит для знаковых сравнений, jb — для беззнаковых. Это важно, если числа могут быть отрицательными или интерпретируются как unsigned

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

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

Как проверить результат на практике

Для ассемблера важно сначала понять, под какую среду написан пример: DOSBox/TASM, Linux x64/NASM, Visual Studio/MASM или микроконтроллер. Один и тот же смысл может записываться разным синтаксисом, поэтому не переносите команды между средами вслепую. Создайте отдельную папку для примера, сохраните файл с расширением .asm, выполните сборку именно тем инструментом, который указан в уроке, и сравните вывод или состояние регистров с ожидаемым результатом

Если пример не собирается, читайте первую ошибку ассемблера: обычно она указывает на строку, неизвестную инструкцию, неверную метку, неправильную секцию или конфликт синтаксиса. Исправляйте одну ошибку за раз. В ассемблере это особенно важно, потому что маленькая опечатка в метке, регистре или размере операнда может полностью изменить поведение программы

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

Настройки cookie

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