Loop ассемблер: Команды LOOP, LOOPD, LOOPE, LOOPNE, LOOPNZ, LOOPZ

Команды 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 и LOOPZ
Синтаксис: LOOPE op1
LOOPZ op1
Операнды: op1
— i8
Назначение: Цикл, пока равно (пока ноль)
Процессор: 8086+
Флаги: Не изменяются
Комментарий:
Ограничения: Поскольку все модификации команды LOOP не изменяют регистр флагов, то флаг ZF должен изменяться внутри тела цикла.
Примеры:

	mov	cx,100
l1:	add	ax,[bx]
	dec	bx
	loope	l1
Команды LOOPNE и LOOPNZ
Синтаксис: LOOPNE op1
LOOPNZ op1
Операнды: op1 — i8
Назначение: Цикл, пока не равно (пока не ноль)
Процессор: 8086+
Флаги: Не изменяются
Комментарий:
Ограничения: Поскольку все модификации команды LOOP не изменяют регистр флагов, то флаг ZF должен изменяться внутри тела цикла.
Примеры:

	mov	cx,100
l1:	add	ax,[bx]
	dec	bx
	loopne	l1

 

Запрашивает число и выводит на экран факториал · GitHub

. 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 , а не с начального , поэтому ваш счетчик циклов не инициализируется.

  • Имена разделов не имеют : в имени, как и метки для global 1

  • Отсутствует параметр для системного вызова 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 трудным путем.
Оставить комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *