2010-02-05 5 views
13

Я написал код так далеко:Как создать цикл на языке ассемблера x86?

.code 

main 
Clrscr 

    mov dh,10   ;row 10 

    mov dl,20   ;column 20 

    call Gotoxy   ;locate cursor 

    PromptForIntegers 

    WriteString  ;display string 
    ReadInt   ;input integer 
    ArraySum 

    WriteString  ;display string 
    WriteInt   ;display integer 

DisplaySum ENDP 

END main 

Как заставить его повторить те же действия, в три раза, используя петлю, очистки экрана после каждой итерации цикла?

+5

Где эти макросы ('WriteInt',' WriteString') пришли? В наши дни сборка x86 унаследована. –

+0

Какой язык ассемблера? http://en.wikipedia.org/wiki/List_of_programming_languages_by_category#Assembly_languages ​​ – Dolph

+2

@mmyers: Что происходит с удалением тега архитектуры? Это важно в сборке. – dmckee

ответ

2

Используйте регистр CX для подсчета петель

 
mov cx, 3 
startloop: 
    cmp cx, 0 
    jz endofloop 
    push cx 
loopy: 
    Call ClrScr 
    pop cx 
    dec cx 
    jmp startloop 
endofloop: 
    ; Loop ended 
    ; Do what ever you have to do here 

Это просто перебирает около 3 раза вызова ClrScr, толкая CX регистр в стек, по сравнению с 0, прыгать, если ZeroFlag установлен, то перейти к endofloop. Обратите внимание, как содержимое CX выталкивается/вынимается из стека, чтобы поддерживать поток цикла.

+1

несколько оптимизаций: (1) вы можете использовать 'jcxz label' вместо' cmp cx, 0' и 'jz label'. (2) вы можете использовать «метку цикла» вместо 'dec cx' и' jnz label' –

+0

@PA: в зависимости от вашего процессора 'jcxz label' и' cmp/jz' эквивалентны. Недавний процессор x86 использует макро-fusion для комбинирования команд cmp/jmp в инструкции с одним циклом, существенно повторяя поведение 'jcxz' на лету. –

+0

Этот цикл невероятно неэффективен. Если цикл может работать с нулевым временем, то проверьте счетчик вне цикла. Затем используйте условную ветвь в конце цикла. И используйте регистр, который вам не нужно будет указывать/вызывать как переменную цикла. (например, регистр с сохранением вызова, подобный (e/r) bx или (e) si, если в вашем цикле есть вызовы функций.). И Джефф Б прав: 'cmp/jz' или' dec/jz' * дешевле *, чем 'jcxz' на современных процессорах, таких как Intel Haswell. См. Http://agner.org/optimize/ –

0

Вам необходимо использовать условные команды jmp. Это не тот синтаксис, который вы используете; выглядит как MASM, но с использованием GAS вот пример из некоторого кода, который я написал для вычисления НОД:

gcd_alg: 
    subl %ecx, %eax  /* a = a - c */ 
    cmpl $0, %eax  /* if a == 0 */ 
    je  gcd_done  /* jump to end */ 
    cmpl %ecx, %eax  /* if a < c */ 
    jl  gcd_preswap  /* swap and start over */ 
    jmp  gcd_alg   /* keep subtracting */ 

В принципе, я сравниваю два регистра с инструкцией CmpL (сравните длину). Если это меньше, команда JL (переход меньше) перескакивает в место предварительного просмотра, в противном случае она возвращается к той же метке.

Что касается очистки экрана, это зависит от используемой вами системы.

+0

'sub% ecx,% eax' уже устанавливает ZF, если результат равен нулю, вам не нужен' cmp $ 0,% eax'. И вы должны структурировать ветвь в конце цикла по-другому: 'jnl gcd_alg'/else попадает в' gcd_preswap'. На самом деле флаги по-прежнему установлены из 'sub', поэтому вы можете' sub% ecx,% eax/jnl gcd_alg/je gcd_done/fall-through в gcd_preswap', поэтому основной цикл - две инструкции. Или просто используйте div, чтобы получить остаток, если 'a' может быть во много раз больше, чем' c'. –

16
mov cx,3 

loopstart: 
    do stuff 
    dec cx   ;Note: decrementing cx and jumping on result is 
    jnz loopstart ;much faster on Intel (and possibly AMD as I haven't 
        ;tested in maybe 12 years) rather than using loop loopstart 
+4

вы можете использовать 'loop loopstart' вместо' dec cx' и 'jnz loopstart', если' do stuff' сохраняет регистр cx. –

+5

@PA: Сохранение cx необходимо, даже если вы не используете 'loop'. –

+1

Это абсолютно правильно, так как вопрос о цикле * три раза. Тем не менее, заголовок вопроса гораздо более общий, и я думаю, что может быть полезно добавить, что если значение cx исходит из переменной, а не из константы, то команда нуля JBE, чтобы перейти к петлевому циклу перед входом в цикл, будет необходимо. –

9

Еще один способ с помощью команды LOOP:

mov cx, 3 

myloop: 
    ; Your loop content 

    loop myloop 

Инструкция цикла автоматически декрементах сх, и скачет, только если сх = 0. Есть также LOOPE и варианты LOOPNE, если вы захотите сделать некоторую дополнительную проверку, чтобы ваш цикл рано вспыхнул.

Если вы хотите изменить сх во время цикла, убедитесь, чтобы поместить его на стек до содержания петли, и выскочить его после:

mov cx, 3 

myloop: 
    push cx 
    ; Your loop content 
    pop cx 

    loop myloop 
+0

Спасибо за помощь – user267288

+0

' loop' [медленно, и использование его не является хорошей привычкой] (http: // stackoverflow.ком/вопросы/35742570/почему-это--петля-инструкция-медленно Couldnt-процессоры Intel уже реализованные-это эффективно). Если вам нужно ecx для чего-то внутри вашего цикла (например, инструкции сдвига), просто используйте другой регистр для счетчика циклов. Наличие push/pop в цепочке зависимостей цикла-счетчика просто глупо. Обычно петли нуждаются в какой-то индукционной переменной, поэтому просто проверяйте это. например увеличивать указатель на 4 каждый раз через цикл и 'cmp/jb' против конечного указателя в качестве условия цикла. –

0

Я искал тот же ответ & нашел эту информацию из вики полезной: инструкции Loop

инструкция цикла декрементирует ECX и переходит к адресу, указанному арг, если декремента ECX не вызывает его значение, чтобы стать равным нулю. Например:

mov ecx, 5 
start_loop: 
; the code here would be executed 5 times 
loop start_loop 

петля не устанавливает никаких флагов.

loopx Arg

Эти петли инструкция декремент ECX и перейти к адресу, указанному аргом, если их условие (то есть, определенный флаг установлен), если декремент ECX не вызывает его значение становятся нулевыми.

  • LOOPE петля, если равно

  • loopne петли, если не равно

  • loopnz петли, если не равен нулю

  • Loopz петли, если нулевой

Источник: X86 Assembly, Control Flow

+0

Работает, но медленнее, чем 'dec/jnz'. –

0
.model small 
.stack 100h 
.code 
Main proc 
Mov cx , 30 ; //that number control the loop 30 means the loop will 
;excite 30 time 
Ioopfront: 
Mov ah , 1 
Int 21h 
Loop loopfront; 

это треск займет 30 символов

+2

Что это значит, что еще не было объяснено в других ответах, опубликованных много лет назад? – Michael

Смежные вопросы