MASM32-SDK (Windows Konsolapplikationen):
Abfragen (IF, SWITCH), Schleifen (REPEAT, LOOP)
und einige Hinweise aus der beim MASM32-SDK mitgelieferten Hilfe

Diese Seite enthält einige Hinweise aus der beim MASM32-SDK mitgelieferten Hilfe.

Zu vermeidende Assemblerbefehle

Laut Abschnitt „Introduction to Assembler / Flat memory Model” sollten einge Assemblerbefehle nicht genutzt werden, da eine individuelle Codierung einen schnelleren Ablauf ergibt:
  • LOOP, LOOPE, LOOPZ, LOOPNZ und LOOPNE
  • Die Stringbefehle MOVS, LODS, CMPS und SCAS und ihre Abarten wie MOVSD, LODSB usw. sollten durch individuelle Codierung ersetzt werden, sofern kein der REP-Operator eingesetzt wird.
  • JCXZ sollte durch
    test ecx, ecx
    je StartLabel
    ersetzt werden.

Empfohlener Standard zur Registersicherung in Prozeduren

  • Die Register EBX, ESI und EDI sollen den Prozedur- bzw. API-Aufruf unbeschadet überstehen.
  • Die Register EAX, ECX und EDX können in der Prozedur frei verwendet werden.
Somit würde man bei der Codierung einer eigenen Prozedur schreiben:
meineprozedur proc .....
    push ebx
    push esi
    push edi

    ; Hier, was in der Prozedur gemacht wird

    pop edi
    pop esi
    pop ebx
    ret
myproc endp
Hinweis: Nur die in der Prozedur geänderten Register Register EBX, ESI und EDI sollten gesichert und wieder hergestellt werden.

Einfache Schleifentechniken

Schleife, die x-mal ausgeführt werden soll

mov edx, 100                ;Anzahl Durchläufe
start:
      ; Hier was gemacht werden soll
      dec edx               ;Schleifenzähler um 1 reduzieren
      jnz start             ;Wiederholen falls noch nicht fertig
Siehe auch Repeat- und While-Schleifen weiter unten auf dieser Webseite.

Byteweise Zeichenkette lesen, bearbeiten und abspeichern

  • Sofern die Zeichenkette nicht mit Null abgeschlossen ist:
          mov esi, src      ;Adresse des Von-Strings nach esi
          mov edi, dst      ;Adresse des Ziel-Strings nach edi
          mov ecx, count    ;Länge des Von-Strings in Bytes
          add ecx, esi      ;plus Adresse des Vonstrings ergibt die
                            ;Endadresse für die Ausführung
    
    start:
          mov al, [esi]      ;Byte aus Von-String lesen
          ; Hier, was mit dem Byte gemacht werden soll
          mov [edi], al      ;Byte im Zieltring ablegen
          inc esi            ;Beide Adresszeiger vorschieben
          inc edi
          cmp ecx, esi      ; Stringende erreicht?
          jne start         ; Noch nicht, also fortsetzen
  • Sofern die Zeichenketten mit Null abgeschlossen sind:
          mov esi, src      ;Adresse des Von-Strings nach esi
          mov edi, dst      ;Adresse des Ziel-Strings nach edi
    
    start:
          mov al, [esi]      ;Byte aus Von-String lesen
          or  al, al         ;Ende erreicht?
          je fertig          ;ja
    
          ; Hier, was mit dem Byte gemacht werden soll
          mov [edi], al      ;Byte im Zieltring ablegen
          inc esi            ;Beide Adresszeiger vorschieben
          inc edi
          jmp start          ;Weiter mit dem nächsten Byte
    
    fertig:
          mov [edi], al      ;Die Schlussnummer Null im Zielstring ablegen

Ablaufsteuerung

Zur Programmablaufsteuerung sind einige Makros vorhanden. Ihr Einsatz bewirkt eine bessere Ingerpretierbarkeit des Quellprogramms.

.if, .elseif, .else, .endif, .until und .while mit Vergeichsoperatoren

Die unterstützten Vergleichsoperatoren sind
==             gleich
!=             ungleich
>              größer als
>=             größer als oder gleich
<              kleiner als
<=             kleiner als oder gleich
&              bitweiser Vergleich im Format Ausdruck & Bitnummer)
!              logisch Nein
&&             logisch Und
||             logisch Oder
CARRY?         Carrybit gesetzt
OVERFLOW?      Überlaufbit gesetzt
PARITY?        Paritätsbit gesetzt
SIGN?          Vorzeichenbit gesetzt
ZERO?          Nullbist gesetzt
  • Einfaches IF:
    Hinweis: Innerhalb einer .if-Abfrage ist keine weitere .if- Abfrage möglich.
    .if variable == wert
      ; hier die Aktion codieren
    .endif
  • IF und ELSE kombiniert:
    .if variable == wert1
      ; hier die Aktion codieren die ggf. durchgeführt werden soll
    .elseif variable != wert2
      ; hier die Aktion codieren die ggf. durchgeführt werden soll
     .else
      ; hier die Aktion codieren, die dann durchgeführt werden soll, wenn
      ; keine der vorhergehenden Aktionen hinter .if und .elseif ausgeführt wurden.
    .endif
    Nur .elseif kann mehrfach auftauchen.

  • Bereichsabfrage:
    .if variable > 50 && variable < 100
      ; hier die Aktion codieren für variable im Wertbereich 51 bis 99
    .else
      ; hier die Aktion codieren für variable außerhalb von 51 bis 99
    .endif
  • switch, case, default und endsw: Die CASE-Abfrage wird ebenfalls unterstützt.
    switch variable
      case wert1
        ; hier die Aktion codieren, die bei variable == wert1 ausgeführt werden soll
      case wert2
        ; hier die Aktion codieren, die bei variable == wert1 ausgeführt werden soll
      default
        ; hier die Aktion codieren, die ausgeführt werden soll, wenn keine
        ; vorhergehende Gleichheitsbedingung zutreffend war.
    endsw
    Es muss mindestens eine case-Zeile vorhanden sein.
    Für Details siehe in \masm32\macros\macros.asm die Makros switch, case, default und endsw sowie das folgende Beispiel:
    .586
    .model flat,stdcall
    .xlist
    option casemap:none
    include \masm32\include\windows.inc
    include \masm32\macros\macros.asm
    include \masm32\include\masm32.inc
    include \masm32\include\user32.inc
    include \masm32\include\kernel32.inc
    include c:\masm32\include\msvcrt.inc
    
    includelib \masm32\lib\masm32.lib
    includelib \masm32\lib\user32.lib
    includelib \masm32\lib\kernel32.lib
    includelib c:\masm32\lib\msvcrt.lib
    .list
    .data
    
    .code
    start:
            MsgBox 0,"Bitte wählen Sie einen Schaltknopf",\
            "Test von switch case default",35
            push eax
    
            switch eax
                case 6 .. 7
                write "Sie bet„tigten Ja oder Nein",13,10
                case 2
                write "Sie bet„tigten Abbrechen",13,10
                default
                write "Wie habe Sie das geschafft?",13,10
            endsw
    
            mov eax,5
    
            switch eax
                case 4 .. 7
                write "Ziffer im Bereich 4 bis 7",13,10
                case 2
                write "Ziffer 2",13,10
                default
                write "alles Andere",13,10
            endsw
    
            pop eax
    
            pop eax
            invoke ExitProcess, eax
    end start
    Messagebox Das Beispiel missbraucht eine Messagebox, um die Zahlen 6=ja, 7=Nein oder 2=Abbrechen in Binärform ins EAX-Register zu liefern. Die Codierung der Schalterabfrage
    case 4 .. 7
    zeigt, wie der Bereich der Zahlen 4, 5, 6 und 7 gemeinsam behandelt werden kann.


Repeat- und While-Schleifen

Die Repeat-Schleife wird so lange durchlaufen, bis eine Endebedingung erfüllt wird. Die Endbedingung wird nach der Aktion abgefragt. Somit wird die Aktion mindestens einmal durchgeführt. Die Aktion muss so codiert werden, dass die nachfolgende Vergeichsoperation zu einem eindeutigen Ergebnis führt.
        .repeat
        ;hier die Aktion codieren.
        ;.until Vergleichsoperation
Bei der While-Schleife wird die Endbedingung vor der Aktion abgefragt. Somit wird die Aktion dann nicht durchgeführt, wenn die Endbedingung bereits vor Eintritt in die While-Schleife erfüllt war. Auch hier gilt, dass die Aktion so codiert werden muss, dass die Vergeichsoperation zu einem eindeutigen Ergebnis führt.
        .while Vergleichsoperation
        ;hier die Aktion codieren.
        ;.endw
Beide Schleifen lassen sich verhältnismäßig einfach ohne Nutzung von .repeat oder .while codieren. Die Nutzung von .repeat oder .while verbessert die Lesbarkeit des Quellcodes.

Beispiel zu .repeat, .until, .if, elseif, .else und endif

Innerhalb der Repeat-Schleife wird die Eingabe einer Zahl im Bereich 1 bis 200 angefordert. Damit mit dem Zahlenwert gerechnet werden kann, muss die aus der Eingabe als String vorliegende Zahleneingabe in eine Integerzahl gewandelt werden. Dies erfolgt durch invoke atodw, lpstring.

Innerhalb .if und .endif wird ein einziger Write-Befehl ausgewählt und angewendet. Seine Anwendung verändert jedoch das eax-Register. Deshalb wird der Inhalt des eax-Registers vor .if gesichert und nach .endif wieder hergestellt.

Das Beispiel demonstriert die Mächtigkeit der beim MASM32-SDK mitgelieferten Beigaben: Das beigegebene atodw erspart die Codierung von etwa 20 Programmzeilen.

Das Beispiel ist nicht umfassend: Es wird nicht geprüft, ob die Eingabe eine Zahl ist. Wenn keine Zahl eingegeben wurde, wird die Eingabe dennoch als Zahl interpretiert.

.586
.model flat,stdcall
.xlist
option casemap:none
include \masm32\include\windows.inc
include \masm32\macros\macros.asm
include \masm32\include\masm32.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include c:\masm32\include\msvcrt.inc

includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib c:\masm32\lib\msvcrt.lib
.list
.data
lpstring       dd ?                     ;zeigt auf den per Input eingetippten String
.code
start:
    .repeat

        write "Bitte geben Sie eine Ganzzahl im Bereich 1 bis 200 ein.",13,10
        write "99 beendet das Programm.",13,10
        mov lpstring, input("Ihre Eingabe: ")


        invoke atodw, lpstring  ;Eingabe konvertieren von String nach Integer
                                ;Integer steht dann in eax

        push    eax             ;sichern wegen der write-Befehle
        .if eax == 99
                write "Das Programmende wurde angefordert",13,10
        .elseif eax > 0 && eax < 201
                write "Die Zahleneingabe war O.K.",13,10
        .else
                write "So nicht!!!",13,10
        .endif
        pop     eax
    .until eax == 99

    inkey                       ;Tastendruck abwarten bei Programmende
    invoke ExitProcess, 0

end start

Ablaufbeispiel:

C:\masm32\Uebung>repeattest
Bitte geben Sie eine Ganzzahl im Bereich 1 bis 200 ein.
99 beendet das Programm.
Ihre Eingabe: 201
So nicht!!!
Bitte geben Sie eine Ganzzahl im Bereich 1 bis 200 ein.
99 beendet das Programm.
Ihre Eingabe: 200
Die Zahleneingabe war O.K.
Bitte geben Sie eine Ganzzahl im Bereich 1 bis 200 ein.
99 beendet das Programm.
Ihre Eingabe: 1
Die Zahleneingabe war O.K.
Bitte geben Sie eine Ganzzahl im Bereich 1 bis 200 ein.
99 beendet das Programm.
Ihre Eingabe: 99
Das Programmende wurde angefordert
Press any key to continue ...

C:\masm32\Uebung>
Letztes Upload: 24.03.2023 um 11:35:14 • Impressum und Datenschutzerklärung