2010-02-05 57 views
13

He escrito el código de la medida en que:¿Cómo hacer un ciclo en el lenguaje ensamblador 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 

¿Cómo llego a repetir los mismos pasos tres veces usando un bucle, la limpieza de la pantalla después de cada iteración del bucle?

+5

dónde estas macros ('WriteInt',' WriteString') vienen? El montaje x86 está bastardeado en estos días. –

+0

¿Qué lenguaje ensamblador es este? http://en.wikipedia.org/wiki/List_of_programming_languages_by_category#Assembly_languages ​​ – Dolph

+2

@mmyers: ¿Qué pasa con la eliminación de la etiqueta de arquitectura? Eso * importa * en el ensamblaje. – dmckee

Respuesta

2

Utilice el registro CX para contar los bucles

 
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 

Esto simplemente se enrolla alrededor de 3 veces llamando ClrScr, empujando el CX se registra en la pila, en comparación con 0, saltando si ZeroFlag se establece a continuación, saltar a endofloop. Observe cómo el contenido de CX es empujado/reventado dentro/fuera de la pila para mantener el flujo del ciclo.

+1

un par de optimizaciones: (1) puede usar 'jcxz label' en lugar de' cmp cx, 0' y 'jz label'. (2) puede usar 'loop label' en lugar de' dec cx' y 'jnz label' –

+0

@PA: Dependiendo de su procesador,' jcxz label' y 'cmp/jz' son equivalentes. Procesador reciente x86 utiliza macro fusión para combinar instrucciones cmp/jmp en una instrucción de ciclo único, esencialmente replicando el comportamiento 'jcxz' sobre la marcha. –

+0

Este ciclo es increíblemente ineficiente. Si un bucle puede ejecutarse cero veces, pruebe el contador fuera del bucle. Luego usa una rama condicional al final del ciclo. Y use un registro que no necesitará pulsar/abrir como su variable de bucle. (por ejemplo, un registro de llamada preservada como (e/r) bx o (e) si si hay llamadas de función en su bucle). Y Jeff B tiene razón: 'cmp/jz' o' dec/jz' es * más barato * que 'jcxz' en CPU modernas como Intel Haswell. Consulte http://agner.org/optimize/ –

0

Debe usar comandos condicional jmp. Esta no es la misma sintaxis que estás usando; Parece que MASM, pero utilizando GAS he aquí un ejemplo de un código que escribí para calcular mcd:

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 */ 

Básicamente, comparar dos registros con la instrucción cmpl (compárese largo). Si es menor, la instrucción JL (saltar menos) salta a la ubicación de preswap, de lo contrario salta a la misma etiqueta.

En cuanto a borrar la pantalla, eso depende del sistema que esté utilizando.

+0

'sub% ecx,% eax' ya establece ZF si el resultado es cero, no necesita' cmp $ 0,% eax'. Y debe estructurar la rama al final del ciclo de la otra manera: 'jnl gcd_alg'/else cae en' gcd_preswap'. En realidad, las banderas todavía están configuradas desde 'sub', por lo que puede' sub% ecx,% eax/jnl gcd_alg/je gcd_done/fall-through en gcd_preswap', por lo que el bucle principal tiene dos instrucciones. O simplemente use div para obtener el resto si 'a' puede ser muchas veces mayor que' 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

puede usar 'loop loopstart' en lugar de' dec cx' y 'jnz loopstart' siempre que' do stuff' conserve el registro cx –

+5

@PA: preservar cx es necesario incluso si no usa 'loop'. –

+1

Esto es absolutamente correcto ya que la pregunta es sobre el bucle * tres * veces. Sin embargo, el título de la pregunta es mucho más genérico y creo que puede ser útil agregar que, si el valor cx proviene de una variable y no de una constante, una instrucción JBE cero, para pasar al loopend antes de ingresar al ciclo, sería necesario. –

9

Otro método es el uso de la instrucción BUCLE:

mov cx, 3 

myloop: 
    ; Your loop content 

    loop myloop 

La instrucción del bucle decrementa automáticamente cx, y sólo si salta cx = 0. También hay LOOPE y variantes LOOPNE, si quiero hacer un control adicional para que tu ciclo salga temprano.

Si desea modificar cx durante su bucle, asegúrese de empujar en la pila antes de que el contenido de bucle, y sacarlo después:

mov cx, 3 

myloop: 
    push cx 
    ; Your loop content 
    pop cx 

    loop myloop 
+0

Gracias por la ayuda – user267288

+0

' loop' [es lento, y usarlo no es una buena costumbre] (http: // stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-inserted-it-efficient). Si necesita ecx para algo dentro de su bucle (por ejemplo, una instrucción de cambio), simplemente use un registro diferente para el contador de bucles. Tener un push/pop en la cadena de dependencia del contador de bucles es una tontería. Por lo general, los bucles necesitan algún tipo de variable de inducción, así que simplemente prueba eso. p.ej. incremente un puntero en 4 cada vez a través del ciclo, y 'cmp/jb' contra un puntero final como condición de ciclo. –

0

que estaba buscando misma respuesta & encontrado esta información de wiki útil: Instrucciones loop

la instrucción del bucle decrementa ECX y salta a la dirección especificada por arg menos decremento ECX causó su valor se convierta en cero. Por ejemplo:

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

El bucle no establece ninguna marca.

loopx arg

Estos bucle ECX instrucciones de decremento y saltar a la dirección especificada por arg si se satisface su condición (es decir, una bandera específica está establecido), a menos que decrementar ECX causado su valor para convertirse en cero.

  • Loope bucle si es igual

  • LOOPNE bucle si no igual

  • LOOPNZ bucle si no es cero

  • loopz bucle si cero

Fuente: X86 Assembly, Control Flow

+0

Funciona, pero más lento que '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; 

este bacalao se llevará a 30 caracteres

+2

¿Qué significa esto que no se haya explicado anteriormente en las otras respuestas publicadas hace años? – Michael

Cuestiones relacionadas