Programmablauf steuern: Unterschied zwischen den Versionen

Aus C und Assembler mit Raspberry
 
(8 dazwischenliegende Versionen desselben Benutzers werden nicht angezeigt)
Zeile 1: Zeile 1:
Grundsätzlich besteht die Programmierung aus vielen wenn/dann Abfragen. Der Ablauf des Programms wird auf bestimmte Bedingungen gesteuert. hier gibt es unter dem ARM-64-Assembler einige BEfehle, wie Bedingte und unbedingte Sprungbefehle: b, bl, cbz, cbnz, die für solche Zwecke verwendet werden können. In diesem Abschnitt erkläre ich, wie diese Verwendet werden kann. In Beispielen erkläre ich noch, wie man bestimmte Anforderungen, wie FOR/NEXT-, WHILE-, DO/UNTIL-Schleifen und IF/ELSE-Abfragen in Assembler abbilden kann.  
Grundsätzlich besteht die Programmierung aus vielen wenn/dann Abfragen. Der Ablauf des Programms wird auf bestimmte Bedingungen gesteuert. Hier gibt es unter dem ARM-64-Assembler einige Befehle, wie bedingte und unbedingte Sprungbefehle: b, bl, cbz, cbnz, die für solche Zwecke verwendet werden können. In diesem Abschnitt erkläre ich, wie diese verwendet werden können. In Beispielen erkläre ich außerdem, wie man bestimmte Anforderungen, wie FOR/NEXT-, WHILE-, DO/UNTIL-Schleifen und IF/ELSE-Abfragen in Assembler abbilden kann.  
== Bedingungsloser Sprung ==
== Bedingungsloser Sprung ==
Der Bedingunslose Sprung wird mit "b" (Branch) durchgeführt. Dies bedeutet, dass der Programmablauf an der mit Label bezeichnetet Stelle springt.
=== b (Branch) ===
Der bedingungslose Sprung wird mit b (Branch) durchgeführt. Dies bedeutet, dass der Programmablauf an die mit einem Label bezeichnete Stelle springt.


Syntax:
Syntax:
Zeile 14: Zeile 15:
     mov x1, #6      // Setze x1 auf 6
     mov x1, #6      // Setze x1 auf 6
     b Label1
     b Label1
     mov x1,#10       //wird übergangen, da Branch auf Label1 springt
     mov x1, #10     // wird übersprungen, da der Branch zu Label1 springt
Label1:
Label1:
     // x1 bleibt auf #6
     // x1 bleibt auf 6
     // Programm beenden
     // Programm beenden
     mov x8, #93      // exit system call
     mov x8, #93      // exit system call
Zeile 22: Zeile 23:
</syntaxhighlight>
</syntaxhighlight>


=== bl (Branch with link) ===
Ein anderer bedingungsloser Sprung ist bl. Dieser wird verwendet, wenn man in ein Unterprogramm springen möchte. Wenn dieser Befehl aufgerufen wird, wird in x30 der darauf folgende Befehl (Adresse) gespeichert. Dies ist sehr nützlich, um von Unterprogrammen wieder zurückzukommen.


* Bedingungsflags
Syntax:
negativ: N gesetzt, wenn Ergebnis negativ ist
<syntaxhighlight lang="asm" inline>bl label</syntaxhighlight>
zero: z gesetzt wenn Ergebnis null ist
 
carry: c gesetzt, wenn es einen Überlauf gab. add -> wenn größer als Zahlenbereich (Überlauf), Subtraktion gesetzt, wenn Ergebnis keine Ausleihe. bei Verschieben letzte Bit herausgeschoben.
Beispiel:
overflow: o gesetzt bei addition und subtraktion, wenn Ergebnis größer oder gleich 2^31, oder kleiner -2^31   
<syntaxhighlight lang="asm">
.global _start
 
_start:
    mov x0, #5        // Setze x0 auf 5
    mov x1, #6        // Setze x1 auf 6
    bl Unterprogramm1 // Springe in das Unterprogramm
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call
 
Unterprogramm1:
    mov x1, #100      // Überschreibe x1 mit 100
    ret              // springe zurück zum Hauptprogramm
</syntaxhighlight>
 
== Bedingter Sprung ==
Bedingte Sprünge werden verwendet, wenn auf bestimmte Ergebnisse reagiert werden soll. Hierfür wird das NZCV-Systemregister verwendet, welches Flags enthält, auf die getestet werden kann.
 
=== Bedingungsflags ===
* negativ (N): Wird gesetzt, wenn das Ergebnis negativ ist.
* zero (Z): Wird gesetzt, wenn das Ergebnis null ist.
* carry (C): Wird gesetzt, wenn es einen Überlauf gab. Bei Addition, wenn größer als Zahlenbereich (Überlauf); bei Subtraktion gesetzt, wenn keine Ausleihe notwendig war; bei Verschieben, wenn das letzte Bit herausgeschoben wurde.
* overflow (V): Wird gesetzt bei Addition und Subtraktion, wenn das Ergebnis größer oder gleich 2^31 oder kleiner als -2^31 ist
 
=== Verzweigung bei Bedingung ===
Für die Verzweigung mit Bedingungen wird ebenfalls b verwendet, allerdings wird ihm eine Bedingung mit übergeben:
 
Syntax:
<syntaxhighlight lang="asm" inline>b.{condition} label</syntaxhighlight>
 
Folgende "conditions" sind möglich:
{| class="wikitable"
|+ condition
|-
! {condition} !! FLAGs !! Bedeutung
|-
| EQ || Z gesetzt || gleich
|-
| NE || Z nicht gesetzt || nicht gleich
|-
| CS oder HS || C gesetzt || größer oder gleich (Vorzeichenlos)
|-
| CC oder LO || C nicht gesetzt || kleiner (Vorzeichenlos)
|-
| MI || N gesetzt || negativ
|-
| PL || N nicht gesetzt || positiv oder Null
|-
| VS || V gesetzt || Überlauf
|-
| VC || V nicht gesetzt || Kein Überlauf
|-
| HI || C gesetzt </br> Z nicht gesetzt || größer (Vorzeichenlos)
|-
| LS || C nicht gesetzt </br> Z gesetzt || kleiner oder gleich (Vorzeichenlos)
|-
| GE || N und V gleich || größer oder gleich (Vorzeichen)
|-
| LT || N und V nicht gleich || kleiner (Vorzeichen)
|-
| GT || Z nicht gesetzt </br> N und V gleich || größer (Vorzeichen)
|-
| LE || Z gesetzt </br> N und V nicht gleich || kleiner oder gleich (Vorzeichen)
|-
| AL || - || Immer (gleiches wie ohne Suffix)
|}
 
Damit die Bedingungen gesetzt werden, müssen vor der Verzweigung die Condition-Flags gesetzt werden. Dies geschieht beispielsweise mit folgenden Befehlen:
 
* Arithmetische Befehle:
** ADDS (Addition mit setzen des Flag)
** SUBS (Subtraktion mit setzen des Flag)
** ADCS (Addition mit Carry und setzen des Flags)
** SBCS (Subtraktion mit Carry und setzen des Flags)
* Logische Befehle
** ANDS (Logisches UND und setzen des Flags)
** TST (Test, Setzt Flags basierend auf AND)
* Weitere Befehle
** CMP (Vergleichen, Setzt Flags basierend auf SUB)
** CMN (Vergleichen mit Negation, Setzt Flags basierend auf ADD)
** NEGS (Negation und setzen des Flags)
 
Beispiel:
<syntaxhighlight lang="asm">
.section .text
.globl _start
 
_start:
    MOV X0, #5      // X0 = 5
    MOV X1, #3      // X1 = 3
   
    ADD X2, X0, X1  // X2 = X0 + X1 = 8, keine Flags gesetzt
    ADDS X3, X0, X1 // X3 = X0 + X1 = 8, Flags gesetzt


Flags werden im NZCV-Systemregister gespeichert
    CMP X2, X3      // Vergleich X2 und X3 (Flags gesetzt)
    B.NE not_equal  // Springe zu not_equal, wenn nicht gleich


* Verzweigung bei Bedingung
    SUBS X4, X0, X1  // X4 = X0 - X1 = 2, Flags gesetzt
-> b.{condition}
{condition} Flags Meaning
EQ Z set Equal
NE Z clear Not equal
CS or HS C set Higher or same (unsigned >=)
CC or LO C clear Lower (unsigned <)
MI N set Negative
PL N clear Positive or zero
VS V set Overflow
VC V clear No overflow
HI C set and Z clear Higher (unsigned >)
LS C clear and Z set Lower or same (unsigned <=)
GE N and V the same Signed >=
LT N and V differ Signed <
GT Z clear, N and V the same Signed >
LE Z set, N and V differ Signed <=
AL Any Always (same as no suffix)


* CMP Xn,Operand2
    B end            // Springe zu end
-> subtrahiert Operand2 von Xn


* Schleifen
not_equal:
** FOR NEXT
    NEG X5, X1      // X5 = -X1 = -3, keine Flags gesetzt
 
end:
    // Endlosschleife um das Programm nicht sofort zu beenden
    B end
</syntaxhighlight>
 
== Spezifischer bedingter Sprung ==
 
Neben den bisher besprochenen bedingungslosen und bedingten Sprungbefehlen gibt es auch spezifische Befehle für Bedingungen, die direkt auf den Wert eines Registers reagieren:
 
=== cbz (Compare and Branch if Zero) ===
 
Der Befehl cbz überprüft, ob der Wert eines Registers null ist und springt dann zu dem angegebenen Label, wenn dies der Fall ist.
 
<syntaxhighlight lang="asm" inline>cbz <register>, <label></syntaxhighlight>
 
Beispiel:
<syntaxhighlight lang="asm">
.global _start
 
_start:
    mov x0, #0      // Setze x0 auf 0
    cbz x0, Label1  // Springe zu Label1, wenn x0 gleich 0 ist
    mov x1, #1      // Dieser Befehl wird übersprungen, weil x0 = 0 ist
Label1:
    // x1 bleibt unverändert
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call
</syntaxhighlight>
 
=== cbnz (Compare and Branch if Not Zero) ===
 
Der Befehl cbnz überprüft, ob der Wert eines Registers nicht null ist und springt dann zu dem angegebenen Label, wenn dies der Fall ist.
 
<syntaxhighlight lang="asm" inline>cbnz <register>, <label></syntaxhighlight>
 
Beispiel:
<syntaxhighlight lang="asm">
.global _start
 
_start:
    mov x0, #5      // Setze x0 auf 5
    cbnz x0, Label1  // Springe zu Label1, wenn x0 ungleich 0 ist
    mov x1, #1      // Dieser Befehl wird übersprungen, weil x0 ≠ 0 ist
Label1:
    // x1 bleibt unverändert
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call
</syntaxhighlight>
 
==== Verwendung von cbz und cbnz in Schleifen und Bedingungen ====
 
Diese Befehle können auch verwendet werden, um einfache Schleifen und Bedingungsstrukturen zu erstellen, ohne die Condition-Flags direkt zu manipulieren.
 
Beispiel einer Schleife mit cbz:
<syntaxhighlight lang="asm">
.global _start
 
_start:
    mov w2, #10      // Setze w2 auf 10
loop:
    // Mache etwas
    sub w2, w2, #1  // w2 = w2 - 1
    cbz w2, loopend  // Springe zu loopend, wenn w2 gleich 0 ist
    b loop          // Wiederhole die Schleife
loopend:
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call
</syntaxhighlight>
 
Beispiel einer Bedingung mit cbnz:
<syntaxhighlight lang="asm">
.global _start
 
_start:
    mov w2, #5      // Setze w2 auf 5
    // Überprüfe, ob w2 ungleich 0 ist
    cbnz w2, condition_met
    // Andernfalls mach etwas anderes
    b condition_not_met
 
condition_met:
    // Code für den Fall, dass die Bedingung erfüllt ist
    b end
 
condition_not_met:
    // Code für den Fall, dass die Bedingung nicht erfüllt ist
 
end:
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call
</syntaxhighlight>
 
== Schleifen ==
In diesem Abschnitt beschreibe ich Beispiele, wie man unter Assembler bestimmte Kontrollstruckturen umsetzen kann, die man auch verschiedenen Hochsprachen, wie zum Beispiel C oder Pascal, kennt.
=== FOR NEXT ===
Pseudocode:
<syntaxhighlight lang="C">
  for i = 1 to 10
  for i = 1 to 10
   Mache etwas
   Mache etwas
  next i
  next i
</syntaxhighlight>


In Assembler:
In Assembler:
<syntaxhighlight lang="asm">
   mov w2,#1  //i=1
   mov w2,#1  //i=1
  loop:
  loop:
Zeile 66: Zeile 249:
   cmp w2,#10  // if i<10
   cmp w2,#10  // if i<10
   b.le loop    // then goto loop
   b.le loop    // then goto loop
** WHILE
</syntaxhighlight>
=== WHILE ===
Pseudocode:
<syntaxhighlight lang="C">
  while x < 10
  while x < 10
   Mache etwas
   Mache etwas
  end while
  end while
</syntaxhighlight>


In Assembler:
In Assembler:
<syntaxhighlight lang="asm">
   // w2 zuvor initialisiert -> x
   // w2 zuvor initialisiert -> x
  // Beispiel: mov w2,#0
   loop:
   loop:
     cmp w2,#10
     cmp w2,#10
     b.ge loopend
     b.ge loopend
     // Mache etwas
     // Mache etwas
    // Beispiel: add w2,w2,#1
     b loop
     b loop
   loopend:
   loopend:
</syntaxhighlight>


** if/then/else
=== if/then/else ===
Pseudocode:
<syntaxhighlight lang="C">
  if x < 10 then
  if x < 10 then
     If ist okay
     If ist okay
Zeile 86: Zeile 279:
     else kommt zum zuge
     else kommt zum zuge
  end if
  end if
</syntaxhighlight>


In Assembler:
In Assembler:
<syntaxhighlight lang="asm">
   // wert x in w2
   // wert x in w2
   cmp w2,#10
   cmp w2,#10
Zeile 96: Zeile 291:
     //else kommt zum zuge
     //else kommt zum zuge
label_EndIf:
label_EndIf:
</syntaxhighlight>


** do/until
=== do/until ===
Pseudocode:
<syntaxhighlight lang="C">
  do
  do
   Mache etwas
   Mache etwas
  until a==0
  until a==0
</syntaxhighlight>


In Assembler:
In Assembler:
<syntaxhighlight lang="asm">
   mov w0,#1
   mov w0,#1
  loop:
  loop:
Zeile 108: Zeile 308:
   cmp w0,#0
   cmp w0,#0
   b.ne loop
   b.ne loop
</syntaxhighlight>

Aktuelle Version vom 3. April 2025, 12:19 Uhr

Grundsätzlich besteht die Programmierung aus vielen wenn/dann Abfragen. Der Ablauf des Programms wird auf bestimmte Bedingungen gesteuert. Hier gibt es unter dem ARM-64-Assembler einige Befehle, wie bedingte und unbedingte Sprungbefehle: b, bl, cbz, cbnz, die für solche Zwecke verwendet werden können. In diesem Abschnitt erkläre ich, wie diese verwendet werden können. In Beispielen erkläre ich außerdem, wie man bestimmte Anforderungen, wie FOR/NEXT-, WHILE-, DO/UNTIL-Schleifen und IF/ELSE-Abfragen in Assembler abbilden kann.

Bedingungsloser Sprung

b (Branch)

Der bedingungslose Sprung wird mit b (Branch) durchgeführt. Dies bedeutet, dass der Programmablauf an die mit einem Label bezeichnete Stelle springt.

Syntax: b label

Beispiel:

.global _start

_start:
    mov x0, #5       // Setze x0 auf 5
    mov x1, #6       // Setze x1 auf 6
    b Label1
    mov x1, #10      // wird übersprungen, da der Branch zu Label1 springt
Label1:
    // x1 bleibt auf 6
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call

bl (Branch with link)

Ein anderer bedingungsloser Sprung ist bl. Dieser wird verwendet, wenn man in ein Unterprogramm springen möchte. Wenn dieser Befehl aufgerufen wird, wird in x30 der darauf folgende Befehl (Adresse) gespeichert. Dies ist sehr nützlich, um von Unterprogrammen wieder zurückzukommen.

Syntax: bl label

Beispiel:

.global _start

_start:
    mov x0, #5        // Setze x0 auf 5
    mov x1, #6        // Setze x1 auf 6
    bl Unterprogramm1 // Springe in das Unterprogramm
    // Programm beenden
    mov x8, #93       // exit system call
    svc 0             // system call

Unterprogramm1:
    mov x1, #100      // Überschreibe x1 mit 100
    ret               // springe zurück zum Hauptprogramm

Bedingter Sprung

Bedingte Sprünge werden verwendet, wenn auf bestimmte Ergebnisse reagiert werden soll. Hierfür wird das NZCV-Systemregister verwendet, welches Flags enthält, auf die getestet werden kann.

Bedingungsflags

  • negativ (N): Wird gesetzt, wenn das Ergebnis negativ ist.
  • zero (Z): Wird gesetzt, wenn das Ergebnis null ist.
  • carry (C): Wird gesetzt, wenn es einen Überlauf gab. Bei Addition, wenn größer als Zahlenbereich (Überlauf); bei Subtraktion gesetzt, wenn keine Ausleihe notwendig war; bei Verschieben, wenn das letzte Bit herausgeschoben wurde.
  • overflow (V): Wird gesetzt bei Addition und Subtraktion, wenn das Ergebnis größer oder gleich 2^31 oder kleiner als -2^31 ist

Verzweigung bei Bedingung

Für die Verzweigung mit Bedingungen wird ebenfalls b verwendet, allerdings wird ihm eine Bedingung mit übergeben:

Syntax: b.{condition} label

Folgende "conditions" sind möglich:

condition
{condition} FLAGs Bedeutung
EQ Z gesetzt gleich
NE Z nicht gesetzt nicht gleich
CS oder HS C gesetzt größer oder gleich (Vorzeichenlos)
CC oder LO C nicht gesetzt kleiner (Vorzeichenlos)
MI N gesetzt negativ
PL N nicht gesetzt positiv oder Null
VS V gesetzt Überlauf
VC V nicht gesetzt Kein Überlauf
HI C gesetzt
Z nicht gesetzt
größer (Vorzeichenlos)
LS C nicht gesetzt
Z gesetzt
kleiner oder gleich (Vorzeichenlos)
GE N und V gleich größer oder gleich (Vorzeichen)
LT N und V nicht gleich kleiner (Vorzeichen)
GT Z nicht gesetzt
N und V gleich
größer (Vorzeichen)
LE Z gesetzt
N und V nicht gleich
kleiner oder gleich (Vorzeichen)
AL - Immer (gleiches wie ohne Suffix)

Damit die Bedingungen gesetzt werden, müssen vor der Verzweigung die Condition-Flags gesetzt werden. Dies geschieht beispielsweise mit folgenden Befehlen:

  • Arithmetische Befehle:
    • ADDS (Addition mit setzen des Flag)
    • SUBS (Subtraktion mit setzen des Flag)
    • ADCS (Addition mit Carry und setzen des Flags)
    • SBCS (Subtraktion mit Carry und setzen des Flags)
  • Logische Befehle
    • ANDS (Logisches UND und setzen des Flags)
    • TST (Test, Setzt Flags basierend auf AND)
  • Weitere Befehle
    • CMP (Vergleichen, Setzt Flags basierend auf SUB)
    • CMN (Vergleichen mit Negation, Setzt Flags basierend auf ADD)
    • NEGS (Negation und setzen des Flags)

Beispiel:

.section .text
.globl _start

_start:
    MOV X0, #5       // X0 = 5
    MOV X1, #3       // X1 = 3
    
    ADD X2, X0, X1   // X2 = X0 + X1 = 8, keine Flags gesetzt
    ADDS X3, X0, X1  // X3 = X0 + X1 = 8, Flags gesetzt

    CMP X2, X3       // Vergleich X2 und X3 (Flags gesetzt)
    B.NE not_equal   // Springe zu not_equal, wenn nicht gleich

    SUBS X4, X0, X1  // X4 = X0 - X1 = 2, Flags gesetzt

    B end            // Springe zu end

not_equal:
    NEG X5, X1       // X5 = -X1 = -3, keine Flags gesetzt

end:
    // Endlosschleife um das Programm nicht sofort zu beenden
    B end

Spezifischer bedingter Sprung

Neben den bisher besprochenen bedingungslosen und bedingten Sprungbefehlen gibt es auch spezifische Befehle für Bedingungen, die direkt auf den Wert eines Registers reagieren:

cbz (Compare and Branch if Zero)

Der Befehl cbz überprüft, ob der Wert eines Registers null ist und springt dann zu dem angegebenen Label, wenn dies der Fall ist.

cbz <register>, <label>

Beispiel:

.global _start

_start:
    mov x0, #0       // Setze x0 auf 0
    cbz x0, Label1   // Springe zu Label1, wenn x0 gleich 0 ist
    mov x1, #1       // Dieser Befehl wird übersprungen, weil x0 = 0 ist
Label1:
    // x1 bleibt unverändert
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call

cbnz (Compare and Branch if Not Zero)

Der Befehl cbnz überprüft, ob der Wert eines Registers nicht null ist und springt dann zu dem angegebenen Label, wenn dies der Fall ist.

cbnz <register>, <label>

Beispiel:

.global _start

_start:
    mov x0, #5       // Setze x0 auf 5
    cbnz x0, Label1  // Springe zu Label1, wenn x0 ungleich 0 ist
    mov x1, #1       // Dieser Befehl wird übersprungen, weil x0 ≠ 0 ist
Label1:
    // x1 bleibt unverändert
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call

Verwendung von cbz und cbnz in Schleifen und Bedingungen

Diese Befehle können auch verwendet werden, um einfache Schleifen und Bedingungsstrukturen zu erstellen, ohne die Condition-Flags direkt zu manipulieren.

Beispiel einer Schleife mit cbz:

.global _start

_start:
    mov w2, #10      // Setze w2 auf 10
loop:
    // Mache etwas
    sub w2, w2, #1   // w2 = w2 - 1
    cbz w2, loopend  // Springe zu loopend, wenn w2 gleich 0 ist
    b loop           // Wiederhole die Schleife
loopend:
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call

Beispiel einer Bedingung mit cbnz:

.global _start

_start:
    mov w2, #5       // Setze w2 auf 5
    // Überprüfe, ob w2 ungleich 0 ist
    cbnz w2, condition_met
    // Andernfalls mach etwas anderes
    b condition_not_met

condition_met:
    // Code für den Fall, dass die Bedingung erfüllt ist
    b end

condition_not_met:
    // Code für den Fall, dass die Bedingung nicht erfüllt ist

end:
    // Programm beenden
    mov x8, #93      // exit system call
    svc 0            // system call

Schleifen

In diesem Abschnitt beschreibe ich Beispiele, wie man unter Assembler bestimmte Kontrollstruckturen umsetzen kann, die man auch verschiedenen Hochsprachen, wie zum Beispiel C oder Pascal, kennt.

FOR NEXT

Pseudocode:

 for i = 1 to 10
   Mache etwas
 next i

In Assembler:

   mov w2,#1  //i=1
 loop:
   //Mache etwas
   add w2,w2,#1 // i=i+1
   cmp w2,#10   // if i<10
   b.le loop    // then goto loop

WHILE

Pseudocode:

 while x < 10
   Mache etwas
 end while

In Assembler:

  // w2 zuvor initialisiert -> x
  // Beispiel: mov w2,#0
  loop:
    cmp w2,#10
    b.ge loopend
    // Mache etwas
    // Beispiel: add w2,w2,#1
    b loop
  loopend:

if/then/else

Pseudocode:

 if x < 10 then
    If ist okay
 else
    else kommt zum zuge
 end if

In Assembler:

  // wert x in w2
  cmp w2,#10
  b.ge label_else
    //If ist okay
    b label_EndIf
label_else:
    //else kommt zum zuge
label_EndIf:

do/until

Pseudocode:

 do
   Mache etwas
 until a==0

In Assembler:

   mov w0,#1
 loop:
   //mache etwas
   cmp w0,#0
   b.ne loop