2010-02-05 10 views
13

Ich habe den Code so weit wie geschrieben:Wie mache ich eine Schleife in x86 Assembler?

.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 

Wie bekomme ich es die gleichen Schritte dreimal mit einer Schleife zu wiederholen, um den Bildschirm nach jeder Schleifeniterationslatenzzeit Clearing?

+5

nehmen Wo haben diese Makros ('WriteInt',' WriteString') kommen? x86-Assembly ist heutzutage bastardisiert. –

+0

Welche Assemblersprache ist das? http://en.wikipedia.org/wiki/List_of_programming_languages_by_category#Assembly_languages ​​ – Dolph

+2

@mmyers: Was ist mit dem Entfernen des Architektur-Tags? Das ist wichtig in der Montage. – dmckee

Antwort

2

das CX-Register Verwenden Sie die Schlaufen

 
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 

Diese einfach umschlingt 3 mal ClrScr Aufruf zu zählen, drängen die CX auf den Stapel registrieren, um eine 0 zu vergleichen, springen, wenn ZeroFlag gesetzt ist, dann zu endofloop springen. Beachten Sie, wie der Inhalt von CX auf den Stapel geschoben/abgelegt wird, um den Fluss der Schleife aufrechtzuerhalten.

+1

ein paar Optimierungen: (1) Sie können 'jcxz label' anstelle von' cmp cx, 0' und 'jz label' verwenden. (2) Sie können 'loop label' anstelle von' dec cx' und 'jnz label' verwenden. –

+0

@PA: Abhängig von Ihrem Prozessor sind' jcxz label' und 'cmp/jz' gleichwertig. Kürzlich verwendete x86-Prozessoren verwenden Makrofusion, um cmp/jmp-Anweisungen zu einer einzigen Zyklusanweisung zu kombinieren, wobei das 'jcxz'-Verhalten im Wesentlichen repliziert wird. –

+0

Diese Schleife ist unglaublich ineffizient. Wenn eine Schleife null Mal ausgeführt wird, dann testen Sie den Zähler außerhalb der Schleife. Verwenden Sie dann eine bedingte Verzweigung am Ende der Schleife. Und verwenden Sie ein Register, das Sie nicht als Loop-Variable drücken müssen. (z.B. ein Anruf-erhaltenes Register wie (e/r) bx oder (e) si, wenn in Ihrer Schleife Funktionsaufrufe vorhanden sind.). Und Jeff B hat Recht: 'cmp/jz' oder' dec/jz' ist * billiger * als 'jcxz' auf modernen CPUs wie Intel Haswell. Siehe http://agner.org/optimize/ –

0

Sie müssen bedingte JMP-Befehle verwenden. Dies ist nicht die gleiche Syntax wie Sie verwenden; sieht aus wie MASM, aber von einigen hier ein Beispiel-Code mit GAS Ich schrieb gcd zu berechnen:

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

Grundsätzlich vergleiche ich zwei Register mit der cmpl Anweisung (vergleiche lang). Wenn es weniger ist, springt der JL-Befehl (sprunglos) zum Preswap-Ort, andernfalls springt er zum selben Label zurück.

Wie zum Löschen des Bildschirms hängt das von dem System ab, das Sie verwenden.

+0

'sub% ecx,% eax' setzt bereits ZF wenn das Ergebnis Null ist, brauchen Sie nicht 'cmp $ 0,% eax'. Und Sie sollten den Zweig am Ende der Schleife anders herum strukturieren: 'jnl gcd_alg'/else fällt in' gcd_preswap'. Tatsächlich werden Flags immer noch von 'sub' gesetzt, also können Sie%% ecx,% eax/jnl gcd_alg/je gcd_done/fall-through in gcd_preswap' setzen, also besteht die Hauptschleife aus zwei Anweisungen. Oder benutze div um den Rest zu erhalten, wenn 'a' um ein Vielfaches größer als' c' ist. –

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

Sie können 'loop loopstart' anstelle von' dec cx' und 'jnz loopstart' verwenden, solange' do stuff' das cx-Register –

+5

@PA speichert: Das Speichern von cx ist notwendig, auch wenn Sie 'loop' nicht verwenden. –

+1

Dies ist absolut korrekt, da die Frage drei mal * Schleifen betrifft. Der Fragetitel ist jedoch viel generischer und ich denke, es könnte nützlich sein, hinzuzufügen, dass, wenn der cx-Wert von einer Variablen und nicht von einer Konstante kommt, ein JBE Zero-Befehl wäre, um zum loopend vor dem Eintritt in die Schleife zu springen erforderlich. –

9

Noch eine andere Methode, um die LOOP-Befehl verwendet:

mov cx, 3 

myloop: 
    ; Your loop content 

    loop myloop 

Die Schleifenanweisung cx automatisch dekrementiert, und springt nur dann, wenn cx = 0. Es gibt auch LOOPE und LOOPNE Varianten, wenn Sie Ich möchte noch ein paar zusätzliche Prüfungen durchführen, damit Ihr Loop früher ausbrechen kann.

Wenn Sie cx während der Schleife ändern möchten, stellen Sie sicher, dass es auf den Stapel vor dem Schleifeninhalt drücken und Pop es ab nach:

mov cx, 3 

myloop: 
    push cx 
    ; Your loop content 
    pop cx 

    loop myloop 
+0

Danke für die Hilfe – user267288

+0

' loop' [ist langsam, und es ist keine gute Gewohnheit] (http: // stackoverflow.com/questions/35742570/why-is-the-Schleife-Anweisung-langsam-konnte nicht-Intel-implementiert-it-effizient). Wenn Sie ecx für etwas innerhalb Ihrer Schleife benötigen (z. B. eine Schiebeanweisung), verwenden Sie einfach ein anderes Register für den Schleifenzähler. Einen Push/Pop in der Loop-Counter-Abhängigkeitskette zu haben, ist einfach albern. Normalerweise benötigen Schleifen eine Art Induktionsvariable, also teste das einfach. z.B. inkrementiere einen Zeiger jedes Mal um 4 durch die Schleife und "cmp/jb" gegen einen Endzeiger als Schleifenbedingung. –

0

Ich war für gleiche Antwort suchen & diese Info gefunden von wiki nützlich: dekrementiert ECX Schleifenanweisungen

die Befehlsschleife und springt auf die Adresse von Arg- angegeben, es sei denn Dekrementieren ECX seinen Wert um Null zu werden verursacht. Zum Beispiel:

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

Schleife setzt keine Flags.

LoopX Arg-

Diese Schleifenbefehle Dekrement ECX und an die von Arg- angegebenen Adresse springen, wenn die Bedingung erfüllt ist (das heißt, ein bestimmte Flag gesetzt ist), es sei denn, ECX Dekrementieren verursachte seinen Wert werde Null.Wenn nicht gleich

  • loopnz loop

    • loope Schleife, wenn gleich

    • loopne Schleife, wenn nicht Null

    • loopz Schleife, wenn Null

    Quelle: X86 Assembly, Control Flow

  • +0

    Funktioniert, aber langsamer als '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; 
    

    diese cod 30 Zeichen

    +2

    Was fügt das hinzu, das in den anderen Antworten, die vor Jahren gepostet wurden, noch nicht erklärt wurde? – Michael

    Verwandte Themen