Команды LOOP, LOOPD, LOOPE, LOOPNE, LOOPNZ, LOOPZ
Команды LOOP, LOOPD, LOOPE, LOOPNE, LOOPNZ, LOOPZ используются для организации циклов. Счетчиком цикла служит регистр CX или ECX (в зависимости от разрядности). В командах циклов с условием (Z, NZ, E, NE) цикл выполняется пока заданное условие истинно.
Команды LOOP, LOOPD
| Синтаксис: | LOOP op1 LOOPD op1 |
| Операнды: | op1 — i8 |
| Назначение: | Цикл |
| Процессор: | 8086+ 80386+ |
| Флаги: | Не изменяются |
| Комментарий: | |
| Ограничения: | Нет |
| Примеры: |
mov cx,100 l1: add ax,[bx] inc bx loop l1 |
| Синтаксис: | LOOPE op1 LOOPZ op1 |
| Операнды: | op1 |
| Назначение: | Цикл, пока равно (пока ноль) |
| Процессор: | 8086+ |
| Флаги: | Не изменяются |
| Комментарий: | |
| Ограничения: | Поскольку все модификации команды LOOP не изменяют регистр флагов, то флаг ZF должен изменяться внутри тела цикла.![]() |
| Примеры: |
mov cx,100 l1: add ax,[bx] dec bx loope l1 |
| Синтаксис: | LOOPNE op1 LOOPNZ op1 |
| Операнды: | op1 — i8 |
| Назначение: | Цикл, пока не равно (пока не ноль) |
| Процессор: | 8086+ |
| Флаги: | Не изменяются |
| Комментарий: | |
| Ограничения: | Поскольку все модификации команды LOOP не изменяют регистр флагов, то флаг ZF должен изменяться внутри тела цикла. |
| Примеры: |
mov cx,100 l1: add ax,[bx] dec bx loopne l1 |
. model tiny | |
| .code | |
| org 100h | |
| pole equ 8 | |
| begin: | |
| mov ah,9h ;функция 9 Выдать строку на дисплей | |
| lea dx,mess ;сообщение DS:DX | |
| int 21h | |
| mov ah,1 ;функция 1 Ввод с клавиатуры AL=вывод | |
| int 21h ;в регистре AL — введеная перемнная | |
| mov x,al ;x=AL | |
| xor cx,cx ;CX=CX-CX | |
| mov cl,al ;CL=AL | |
| sub cl,30h ;CL=CL-30h в регистре CL число(преобразуем в число) | |
| mov dl,cl ;DL=CL запомнили число(преобразованное число=DL) | |
| mov ax,01h ;AX=1 подготовка к вычислению факториала | |
| mov bl,01h ;BL=1 AX=1 Dl=Число Cl=Число X=символ числа | |
| cloop: | |
| mul bl ;AX=BL*AX | |
| inc bl ;BL=BL+1 | |
| loop cloop ;goto CLOOP when CX>0 | |
| ;цикл повторяется CX | |
| ;в CL находится число | |
| ;CL это младший регистр CX | |
| ;CX=00[CL] | |
| ;в регистре AX факториал | |
| ;преобразование числа в регистре AX в цепочку цифр | |
| lea si,z+pole-1 ;SI=[8 dup(‘ ‘)]-1 | |
| mov bx,0ah ;BX=Ah делить 2 байтовый | |
| nach: | |
| ;xor dx,dx ;dx=0 очищаем регистр перед делением | |
| div bx ;AX=DX:AX/BX DX=ОСТАТОК | |
| ;если dx=2030h ax=0040h DX:AX=20300040h | |
| ;DX:AX значение DWORD | |
| ;ПОЭТОМУ НАДО ОБНУЛЯТЬ DX перед делением | |
| cmp ax,0 ;ax-0 | |
| ;проверка результата деления, если число | |
| ;однозначное то на выход | |
| ;если больше двух знаков продолжать деление | |
| je kon ;if ax=0 goto kon; je=jz | |
| add dl,30h ;dl=dl+30h dl становится символом | |
| ;dl это младший регистр dx | |
| ;dx=остаток от деления | |
| ;dl=остаток от деления в виде бита | |
| mov [si],dl ;[si]=dl [si]=z+pole-1 | |
| ;пересылка символа dl В КОНЕЦ СТРОКИ | |
| ;si=адрес текущего конца строки | |
dec si ;si=si-1.![]() | |
| ;Уменьшаем адрес конца строки на единицу | |
| jmp nach ;GOTO nach | |
| kon: | |
| ;В регистре SI колличество цифр в результата | |
| add dl,30h ;код цифр старшего разряда | |
| mov [si],dl ;переслали введеную цифру в поле ввода | |
| ;вывод на экран | |
| mov ah,9 ;Функция 9 Выдать строку на дисплей | |
lea dx,ans ;Адрес начала строки. Выводится всё по порядку до знака $. | |
| int 21h | |
| ret | |
| mess db «Введите число <=9:»,0dh,0ah,»$» | |
| ans db 0dh,0ah, «Факториал « | |
| x db ?,» равен « | |
| z db Pole dup (‘ ‘) ;поле вывода | |
| db 0dh,0ah ,’$’ | |
| end begin |
linux — бесконечный цикл ассемблера NASM с регистром cx
спросил
Изменено 3 года, 5 месяцев назад
Просмотрено 272 раза
раздел .данные: msg1: db "Привет 10 раз!" msglen1: equ $-msg1 раздел .текст: глобальный _initial: глобальный _start: глобальный _end: _исходный: мов сх, 10 _Начало: дек сх мов ecx, msg1 мов edx, msglen1 мов акс,4 интервал 80ч cmp сх,0 jz _end jmp _start _конец мов акс,1 интервал 80ч
В приведенном выше коде должно было быть 10 раз выведено «Hello 10 times». Но это привело к бесконечному циклу, и я не мог понять, почему? я думаю, регистр cx не уменьшается или что-то еще?
- linux
- сборка
- x86
- nasm
- системные вызовы
1
У вас ряд проблем.
Точкой входа по умолчанию для программы Linux является
_start. Ваша программа начинается с выполнения с метки_start, а не сначального, поэтому ваш счетчик циклов не инициализируется.
Имена разделов не имеют
:в имени, как и метки дляglobal1Отсутствует параметр для системного вызова
SYS_Write. 32-битные системные вызовы задокументированы в таблице:Необходимо установить EBX в дескриптор файла. СТАНДАРТНЫЙ ВХОД = 0, СТАНДАРТНЫЙ ВЫХОД = 1, СТАНДАРТНЫЙ ВЫВОД = 2. Вы хотите писать в консоль, поэтому вам нужно установить EBX в 1 перед вызовом
Int 80hВы затираете один из параметров ( ECX ) системного вызова
SYS_Write. CX и ECX являются частью одного регистра. CX — это младшие 16 бит ECX . Изменение CX изменение ECX . Вам нужно использовать какой-то другой регистр для счетчика циклов. ESI , EDI и EBP в настоящее время не используются в вашем коде. Измените все вхождения CX на 32-битный регистр ESI .
Ваш код может выглядеть так:
раздел .data
msg1: db "Привет 10 раз!", 10
; Добавьте 10 в конец строки для перевода строки
; поэтому каждое сообщение печатается на отдельной строке
msglen1 equ $-msg1
раздел .текст
глобальный _initial
глобальный _start
глобальный _end
_Начало:
мов эси, 10 ; Инициализировать счетчик циклов
_msgloop:
дек эси ; Уменьшить счетчик циклов
мов ebx, 1 ; Файловый дескриптор 1 = запись в стандартный вывод (STDOUT)
mov ecx, msg1 ; Адрес сообщения для печати
мов edx, msglen1 ; Длина сообщения для печати
мов акс, 4 ; Системный вызов SYS_Write = 4
интервал 80ч
cmp esi, 0 ; Счетчик циклов достиг 0?
jz _end ; Если это так, то мы закончили
jmp _msgloop ; в противном случае вернитесь и напечатайте сообщение снова
_конец:
дв акс,1 ; Системный вызов SYS_Exit
интервал 80ч
Вы могли бы переписать свой цикл так:
section .data msg1: db "Привет 10 раз!", 10 ; Добавьте 10 в конец строки для перевода строки ; поэтому каждое сообщение печатается на отдельной строке msglen1 equ $-msg1 раздел .текст глобальный _start _Начало: мов эси, 10 ; Инициализировать счетчик циклов .msgloop: мов ebx, 1 ; Файловый дескриптор 1 = запись в стандартный вывод (STDOUT) mov ecx, msg1 ; Адрес сообщения для печати мов edx, msglen1 ; Длина сообщения для печати мов акс, 4 ; Системный вызов SYS_Write = 4 интервал 80ч дек эси ; Уменьшить счетчик циклов jnz .msgloop ; Если счетчик циклов не достиг нуля, снова напечатайте дв акс,1 ; Системный вызов SYS_Exit интервал 80ч
Сноски:
- 1 Вам не нужно делать
начальнымиконечнымглобальными, поскольку вы не связываетесь ни с какими другими объектными файлами.
Эти глобальныхстроки можно удалить.
0
Вы пытаетесь использовать регистр cx для подсчета циклов, в то время как вам нужно использовать ecx в качестве параметра для вашего вывода. Поскольку cx — это младшие 16 бит из ecx , вы сбиваете количество циклов.
Вам нужно либо использовать какой-то другой регистр (который не используется во время системного вызова) для счетчика циклов, либо сохранить счетчик в локальной переменной в стеке.
3
Зарегистрируйтесь или войдите в систему
Зарегистрируйтесь с помощью Google
Зарегистрироваться через Facebook
Зарегистрируйтесь, используя электронную почту и пароль
Опубликовать как гость
Электронная почта
Обязательно, но не отображается
Опубликовать как гость
Электронная почта
Требуется, но не отображается
Если, циклы и инструкция DBRA
Если, циклы и инструкция DBRAЕСЛИ
Простой IF
а)ГЛЛ б) 68К x:=x+1 ADDQ.W #1,X ЕСЛИ A=7, ТО CMPI.W #7,A Б:=3; БНЭ СЛЕДУЮЩИЙ С:=4; МОВЭК #3,Б КОНЕЦ, ЕСЛИ ДВИЖЕНИЕ #4,C х:=Х+2; СЛЕДУЮЩИЙ: ДОБАВИТЬQ.W #2,X б) на ГВУ ЕСЛИ Х=2, ТО КОД:=2; КОД:=1; изменить на ЕСЛИ X=2 ТО ДРУГОЙ КОД:=1; КОД:=2; КОНЕЦ ЕСЛИ КОНЕЦ ЕСЛИ Это упрощает код. в) ОБЩИЙ КОНТУР ХЛЛ 68К ЕСЛИ (I>GT> 0), ТО CMPI.W #0,I КОД(A) ДРУГОЕ ДРУГОЙ КОД(А) КОД(B) БЮСТГАЛЬТЕР NEXT КОНЕЦ, ЕСЛИ ЕЩЕ: КОД(В) СЛЕДУЮЩИЙ СЛЕДУЮЩИЙ: г) Я никогда не хочу видеть: ВЕЩИ БЮСТГАЛЬТЕР NEXT заменить на NEXT: СЛЕДУЮЩИЙ: Вы хотите уменьшить количество веток, не ставя лишние.
Петли
В мире существует два типа циклов — циклы ПОВТОР и циклы ПОКА. Повторяющиеся циклы всегда выполняются один раз, что является редкостью для циклов. Ты должен всегда проверяйте себя, чтобы увидеть, безопасно ли использовать повторяющийся цикл. Какое-то время цикл может быть выполнен ноль раз и всегда безопасен и очень распространен в программирование.
ПОВТОР Циклы
а) Стандартный повторяющийся цикл
ПОВТОР: Чтение с часовым
JSR DECIN подходит для повторной петли.
ЦМП.В '-1',d0
ПОВТОР БНЭ
б) Общий цикл
Петля:
CODE(A) Так как CODE(A) всегда выполнял это
CMPI.W #0,I — повторяющийся цикл.
БЛТ СЛЕДУЮЩИЙ
КОД(В)
БЮСТГАЛЬТЕР
Пока цикл
а) ОК ВЕРСИЯ б) Лучшая версия
ПРЕДЫДУЩИЙ КОД ПРЕДЫДУЩИЙ КОД
Петля: БЮСТГАЛЬТЕР CHECK
CMP --- ЦИКЛ:
BEQ ENDLOOP CODE(C)
ПРОВЕРКА КОД(С):
БЮСТГАЛЬТЕР LOOP CMP ---
КОНЕЦ ПЕТЛИ: BNE LOOP
СЛЕДУЮЩИЙ КОД СЛЕДУЮЩИЙ КОД
Некоторые общие сведения о циклах
- Большинство циклов проходят «высшее тестирование» (например, циклы WHILE в Pascal или С). Это верно в большинстве случаев.
- Условие цикла должно быть проверено перед выполнением тела
петли в первый раз, а не после. Это позволяет телу цикла
выполняться 0 раз, если это уместно. В некоторых случаях
цикл повторения до тех пор, пока цикл выбора.

- В языке ассемблера условный переход будет проверять условие цикла.
- Это не означает, что условная ветвь должна появляться в хотя начало цикла на ассемблере. Обычно это должно быть размещается внизу, и должна быть безусловная ветвь к нижней части цикла, чтобы начать. Иногда, если петля очень долго эта процедура не соблюдается.
- Какая разница?
- В первом внутри петли две ветви.
- Во втором внутри цикла всего одна ветвь. Другой один находится вне цикла, где он выполняется только один раз, а не на каждой итерации.
- Особенно в современных конвейерных процессорах очень важно чтобы свести к минимуму количество ветвей и упростить структуру петель.
Инструкция DBRA 68000k
- Синтаксис инструкции dbra (уменьшение и переход) следующий:
дБА Di,Addr
- Эта инструкция уменьшает Di.
w и переходит к Addr, если результат
не -1. - Эквивалент следующих 3 инструкций
sub.w #1, Di cmp.w #-1, Di bne Адрес
- Это очень типичная инструкция CISC. В программе для RISC-машины вы бы использовали три отдельные инструкции.
- Его цель — упростить «циклы, контролируемые счетом». (Который то есть, если вы заранее точно знаете, сколько раз должен выполняться цикл, воспользуйтесь этой инструкцией.)
- Чтобы выполнить цикл ровно N раз, используйте этот код:
move.w N,D2 ;Поместите N в регистр D, если его еще нет bra EndL ;Начните с инструкции dbra внизу Петля: ... ... EndL: dbra D2, Loop
- Это «правильный» тип петли, только с одной ветвью в оно, внизу. Цикл вводится путем перехода к «dbra» внизу.
- Это также объясняет, почему инструкция dbra проверяет -1, а не 0.

- Если вы хотите использовать значения в регистре, они Н-1,Н-2,…1,0.
- Вот два неверных способа сделать это:
ход.w N,D1 Петля: ... ... петля dbra
- Приведенный выше цикл выполняется N+1 раз, а не N раз.
- Итак, как насчет того, чтобы сначала уменьшить N, чтобы решить эту проблему?
ход.w N,D1 sub.w #1,D1 Петля: ... ... петля dbra
- Приведенный выше цикл содержит огромную ошибку . Если N=0, цикл не будет
быть выполнено 0 раз (что правильно). Вместо этого будет выполнено 65536
раз!! (В первый раз «dbra» будет уменьшаться на -1
и получите -2. Это не -1, поэтому он будет продолжаться. Значение в D1 будет
нужно считать до -32768, переполниться до +32767 и продолжить
вниз, пока он, наконец, не достигнет -1 трудным путем.



model tiny
Выводится всё по порядку до знака $.
данные:
msg1: db "Привет 10 раз!"
msglen1: equ $-msg1
раздел .текст:
глобальный _initial:
глобальный _start:
глобальный _end:
_исходный:
мов сх, 10
_Начало:
дек сх
мов ecx, msg1
мов edx, msglen1
мов акс,4
интервал 80ч
cmp сх,0
jz _end
jmp _start
_конец
мов акс,1
интервал 80ч


data
msg1: db "Привет 10 раз!", 10
; Добавьте 10 в конец строки для перевода строки
; поэтому каждое сообщение печатается на отдельной строке
msglen1 equ $-msg1
раздел .текст
глобальный _start
_Начало:
мов эси, 10 ; Инициализировать счетчик циклов
.msgloop:
мов ebx, 1 ; Файловый дескриптор 1 = запись в стандартный вывод (STDOUT)
mov ecx, msg1 ; Адрес сообщения для печати
мов edx, msglen1 ; Длина сообщения для печати
мов акс, 4 ; Системный вызов SYS_Write = 4
интервал 80ч
дек эси ; Уменьшить счетчик циклов
jnz .msgloop ; Если счетчик циклов не достиг нуля, снова напечатайте
дв акс,1 ; Системный вызов SYS_Exit
интервал 80ч
Эти
W #1,X
ЕСЛИ A=7, ТО CMPI.W #7,A
Б:=3; БНЭ СЛЕДУЮЩИЙ
С:=4; МОВЭК #3,Б
КОНЕЦ, ЕСЛИ ДВИЖЕНИЕ #4,C
х:=Х+2; СЛЕДУЮЩИЙ:
ДОБАВИТЬQ.W #2,X
б) на ГВУ
ЕСЛИ Х=2, ТО КОД:=2;
КОД:=1; изменить на ЕСЛИ X=2 ТО
ДРУГОЙ КОД:=1;
КОД:=2; КОНЕЦ ЕСЛИ
КОНЕЦ ЕСЛИ
Это упрощает код.
в) ОБЩИЙ КОНТУР
ХЛЛ 68К
ЕСЛИ (I>GT> 0), ТО CMPI.W #0,I
КОД(A) ДРУГОЕ
ДРУГОЙ КОД(А)
КОД(B) БЮСТГАЛЬТЕР NEXT
КОНЕЦ, ЕСЛИ ЕЩЕ:
КОД(В)
СЛЕДУЮЩИЙ СЛЕДУЮЩИЙ:
г) Я никогда не хочу видеть:
ВЕЩИ
БЮСТГАЛЬТЕР NEXT заменить на NEXT:
СЛЕДУЮЩИЙ:
Вы хотите уменьшить количество веток, не ставя лишние.

w и переходит к Addr, если результат
не -1.
