ARM64 Assembly für Einsteiger – Teil 3: Bedingungen, Schleifen und Kontrollfluss
Einleitung
Bisher konnten unsere Programme nur linear ablaufen – Zeile für Zeile, von oben nach unten. Echte Programme brauchen aber Entscheidungen und Wiederholungen.
In diesem Teil lernst du:
- Wie man Werte vergleicht
- Bedingte Sprünge (if/else)
- Schleifen (while/for)
- Wie man komplexe Programmabläufe steuert
Labels – Sprungziele im Code
Was ist ein Label?
Ein Label ist ein Name für eine bestimmte Stelle im Code – wie ein Lesezeichen. Du kannst zu diesem Label springen.
.global _start
.align 2
.text
_start:
mov x0, #5
b springe_hierhin // Springe zum Label
mov x0, #99 // Wird übersprungen!
springe_hierhin:
mov x1, #10
// x0 = 5, x1 = 10 (die Zeile mit #99 wurde nie ausgeführt)
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Wichtig:
- Labels enden mit einem Doppelpunkt
: b= Branch (unbedingter Sprung)- Der Code bei
mov x0, #99wird nie erreicht!
Vergleiche – Die Basis für Entscheidungen
Der CMP-Befehl
cmp (Compare) vergleicht zwei Werte und setzt interne Flags:
cmp x0, x1 // Vergleiche x0 mit x1
Der CMP-Befehl verändert die Register nicht, sondern setzt nur unsichtbare Condition Flags:
- Z (Zero) – Sind die Werte gleich?
- N (Negative) – Ist das Ergebnis negativ?
- C (Carry) – Gab es einen Übertrag?
- V (Overflow) – Gab es einen Überlauf?
Diese Flags kannst du mit bedingten Sprüngen abfragen!
Bedingte Sprünge
Die wichtigsten Bedingungen
| Befehl | Bedeutung | Bedingung |
|---|---|---|
b.eq | Branch if Equal | Wenn gleich |
b.ne | Branch if Not Equal | Wenn ungleich |
b.lt | Branch if Less Than | Wenn kleiner (signed) |
b.le | Branch if Less or Equal | Wenn kleiner oder gleich |
b.gt | Branch if Greater Than | Wenn größer (signed) |
b.ge | Branch if Greater or Equal | Wenn größer oder gleich |
b.lo | Branch if Lower | Wenn kleiner (unsigned) |
b.hi | Branch if Higher | Wenn größer (unsigned) |
Erstes Beispiel: Einfacher Vergleich
.global _start
.align 2
.text
_start:
mov x0, #5
mov x1, #10
cmp x0, x1 // Vergleiche 5 mit 10
b.eq sind_gleich // Springe wenn gleich
b.lt ist_kleiner // Springe wenn x0 < x1
b sind_groesser // Sonst (x0 > x1)
sind_gleich:
mov x2, #1 // x2 = 1 (gleich)
b ende
ist_kleiner:
mov x2, #2 // x2 = 2 (kleiner)
b ende
sind_groesser:
mov x2, #3 // x2 = 3 (größer)
b ende
ende:
// x2 = 2, weil 5 < 10
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Ablauf:
cmp x0, x1vergleicht 5 mit 10b.eq sind_gleichwird übersprungen (5 ≠ 10)b.lt ist_kleinerwird ausgeführt (5 < 10)- Sprung zu
ist_kleiner mov x2, #2b endespringt zum Ende
If/Else in Assembly
Pattern: if (a > b) then … else …
In einer höheren Sprache:
if (x0 > x1) {
x2 = 100;
} else {
x2 = 200;
}
In Assembly:
cmp x0, x1 // Vergleiche
b.le else_teil // Wenn x0 <= x1, gehe zu else
// If-Teil
mov x2, #100
b ende
else_teil:
// Else-Teil
mov x2, #200
ende:
// Weiter im Programm
Praktisches Beispiel: Maximum finden
.global _start
.align 2
.data
zahl_a:
.quad 42
zahl_b:
.quad 17
maximum:
.quad 0
.text
_start:
// Lade zahl_a
adrp x0, zahl_a@PAGE
add x0, x0, zahl_a@PAGEOFF
ldr x1, [x0] // x1 = 42
// Lade zahl_b
adrp x0, zahl_b@PAGE
add x0, x0, zahl_b@PAGEOFF
ldr x2, [x0] // x2 = 17
// Vergleiche
cmp x1, x2
b.gt a_ist_groesser
// b ist größer oder gleich
mov x3, x2
b weiter
a_ist_groesser:
mov x3, x1
weiter:
// Speichere Maximum
adrp x0, maximum@PAGE
add x0, x0, maximum@PAGEOFF
str x3, [x0] // maximum = 42
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Schleifen – Code wiederholen
Die grundlegende While-Schleife
In einer höheren Sprache:
int i = 0;
while (i < 5) {
i = i + 1;
}
In Assembly:
.global _start
.align 2
.text
_start:
mov x0, #0 // i = 0
mov x1, #5 // Limit = 5
loop:
add x0, x0, #1 // i++
cmp x0, x1 // Vergleiche i mit 5
b.lt loop // Wenn i < 5, wiederhole
// Schleife endet, x0 = 5
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Ablauf:
Start: x0 = 0
Loop 1: x0 = 1, 1 < 5? Ja → weiter
Loop 2: x0 = 2, 2 < 5? Ja → weiter
Loop 3: x0 = 3, 3 < 5? Ja → weiter
Loop 4: x0 = 4, 4 < 5? Ja → weiter
Loop 5: x0 = 5, 5 < 5? Nein → Ende
Beispiel: Summe von 1 bis 10
.global _start
.align 2
.text
_start:
mov x0, #1 // Zähler = 1
mov x1, #10 // Bis 10
mov x2, #0 // Summe = 0
summen_loop:
add x2, x2, x0 // Summe += Zähler
add x0, x0, #1 // Zähler++
cmp x0, x1
b.le summen_loop // Wiederhole wenn x0 <= 10
// x2 = 1+2+3+4+5+6+7+8+9+10 = 55
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Countdown-Schleife
.global _start
.align 2
.text
_start:
mov x0, #10 // Start bei 10
countdown:
sub x0, x0, #1 // x0--
cmp x0, #0 // Ist x0 == 0?
b.ne countdown // Wenn nicht 0, wiederhole
// x0 = 0
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Schleifen mit Arrays
Alle Array-Elemente durchgehen
.global _start
.align 2
.data
zahlen:
.quad 5, 10, 15, 20, 25
.text
_start:
// Startadresse
adrp x0, zahlen@PAGE
add x0, x0, zahlen@PAGEOFF
mov x1, #0 // Offset = 0
mov x2, #40 // Ende (5 Zahlen × 8 Bytes = 40)
mov x3, #0 // Summe = 0
loop:
ldr x4, [x0, x1] // Lade zahlen[offset]
add x3, x3, x4 // Summe += x4
add x1, x1, #8 // Offset += 8
cmp x1, x2 // Offset < 40?
b.lt loop
// x3 = 5+10+15+20+25 = 75
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Wie es funktioniert:
- x0 = Basis-Adresse des Arrays
- x1 = Aktueller Offset (0, 8, 16, 24, 32)
ldr x4, [x0, x1]= Lade von Adresse (x0 + x1)
Alternative: Mit Index-Register
.global _start
.align 2
.data
zahlen:
.quad 10, 20, 30, 40, 50
.text
_start:
adrp x0, zahlen@PAGE
add x0, x0, zahlen@PAGEOFF
mov x1, #0 // Index = 0
mov x2, #5 // Anzahl Elemente
mov x3, #0 // Summe = 0
loop:
// Berechne Offset: Index × 8
lsl x4, x1, #3 // x4 = x1 << 3 = x1 × 8
ldr x5, [x0, x4] // Lade Element
add x3, x3, x5 // Addiere zur Summe
add x1, x1, #1 // Index++
cmp x1, x2 // Index < 5?
b.lt loop
// x3 = 150
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Neuer Befehl: lsl = Logical Shift Left (Linksverschiebung)
lsl x4, x1, #3verschiebt x1 um 3 Bits nach links- Das ist dasselbe wie × 8 (2³ = 8)
Verschachtelte Bedingungen
Mehrere If-Abfragen
.global _start
.align 2
.text
_start:
mov x0, #15 // Zu prüfende Zahl
mov x1, #0 // Ergebnis-Code
// Prüfe ob < 10
cmp x0, #10
b.ge nicht_klein
mov x1, #1 // Code 1: klein
b ende
nicht_klein:
// Prüfe ob < 20
cmp x0, #20
b.ge nicht_mittel
mov x1, #2 // Code 2: mittel
b ende
nicht_mittel:
// Prüfe ob < 30
cmp x0, #30
b.ge gross
mov x1, #3 // Code 3: groß
b ende
gross:
mov x1, #4 // Code 4: sehr groß
ende:
// x1 = 2 (weil 15 zwischen 10 und 20 liegt)
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Praktische Beispiele
Beispiel 1: Fakultät berechnen
Fakultät von n = n × (n-1) × (n-2) × … × 1
.global _start
.align 2
.text
_start:
mov x0, #5 // n = 5
mov x1, #1 // Ergebnis = 1
fakultaet_loop:
mul x1, x1, x0 // Ergebnis *= n
sub x0, x0, #1 // n--
cmp x0, #1 // n > 1?
b.gt fakultaet_loop
// x1 = 5! = 5×4×3×2×1 = 120
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Beispiel 2: Maximum in Array finden
.global _start
.align 2
.data
zahlen:
.quad 23, 67, 12, 89, 34, 56
.text
_start:
adrp x0, zahlen@PAGE
add x0, x0, zahlen@PAGEOFF
ldr x1, [x0] // x1 = erstes Element (aktuelles Max)
mov x2, #8 // Offset (starte bei 2. Element)
mov x3, #48 // Ende (6 × 8 = 48)
find_max_loop:
ldr x4, [x0, x2] // Lade nächstes Element
cmp x4, x1 // Ist es größer als aktuelles Max?
b.le nicht_groesser
mov x1, x4 // Neues Maximum
nicht_groesser:
add x2, x2, #8 // Nächstes Element
cmp x2, x3 // Noch nicht am Ende?
b.lt find_max_loop
// x1 = 89 (das Maximum)
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Beispiel 3: Bubble Sort (vereinfacht)
Sortiert zwei Zahlen, wenn sie in falscher Reihenfolge sind:
.global _start
.align 2
.data
zahl1:
.quad 42
zahl2:
.quad 17
.text
_start:
// Lade beide Zahlen
adrp x0, zahl1@PAGE
add x0, x0, zahl1@PAGEOFF
ldr x1, [x0] // x1 = 42
adrp x0, zahl2@PAGE
add x0, x0, zahl2@PAGEOFF
ldr x2, [x0] // x2 = 17
// Vergleiche
cmp x1, x2
b.le richtige_reihenfolge
// Tausche
adrp x0, zahl1@PAGE
add x0, x0, zahl1@PAGEOFF
str x2, [x0] // zahl1 = 17
adrp x0, zahl2@PAGE
add x0, x0, zahl2@PAGEOFF
str x1, [x0] // zahl2 = 42
richtige_reihenfolge:
// Jetzt: zahl1 = 17, zahl2 = 42
// Exit
mov x0, #0
mov x16, #1
svc #0x80
Übungen
Übung 1: Gerade oder Ungerade
Schreibe ein Programm, das prüft ob eine Zahl gerade ist:
- Wenn gerade: x1 = 0
- Wenn ungerade: x1 = 1
Hinweis: Nutze bitweise AND: and x1, x0, #1 (prüft das niedrigste Bit)
Übung 2: Countdown mit Ausgabe
Erweitere die Countdown-Schleife so, dass jede Zahl als Ziffer ausgegeben wird. Nutze das Wissen aus Teil 1 über Syscalls.
Übung 3: Fibonacci-Zahlen
Berechne die ersten 10 Fibonacci-Zahlen:
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, ...
Formel: F(n) = F(n-1) + F(n-2)
Übung 4: Minimum und Maximum
Schreibe ein Programm, das sowohl Minimum als auch Maximum in einem Array findet.
Debugging-Tipps
Häufige Fehler bei Schleifen
Endlosschleife:
// FALSCH:
loop:
add x0, x0, #1
cmp x0, #10
b.lt loop // Springt immer zurück!
Problem: Keine Abbruchbedingung wenn x0 schon >= 10 war!
Off-by-one Fehler:
// Soll bis 10 zählen (inkl. 10)
mov x0, #1
loop:
add x0, x0, #1
cmp x0, #10
b.lt loop // Stoppt bei 10, aber führt 10 nicht mehr aus!
// Richtig:
b.le loop // <= statt <
Debugging mit lldb (macOS Debugger)
Du kannst dein Programm Schritt für Schritt ausführen:
# Kompiliere mit Debug-Info
as -g -o programm.o programm.s
ld -o programm programm.o -lSystem -syslibroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -e _start -arch arm64
# Starte Debugger
lldb programm
# Im lldb:
(lldb) breakpoint set --name _start
(lldb) run
(lldb) register read # Zeige alle Register
(lldb) step # Nächste Instruktion
(lldb) continue # Weiter ausführen
Zusammenfassung
In diesem Teil hast du gelernt:
- ✅ Labels markieren Positionen im Code
- ✅
cmpvergleicht Werte und setzt Flags - ✅ Bedingte Sprünge:
b.eq,b.lt,b.gt, etc. - ✅ If/else durch Vergleich + bedingte Sprünge
- ✅ Schleifen = Label + Vergleich + bedingter Sprung zurück
- ✅ Arrays mit Schleifen durchlaufen
- ✅ Praktische Algorithmen (Maximum, Fakultät, Sortierung)
Nächste Schritte
Im nächsten Teil lernst du Funktionen und den Stack:
- Funktionen aufrufen und zurückkehren
- Parameter übergeben
- Lokale Variablen
- Der Stack (Stapelspeicher)
- Calling Conventions
Damit kannst du dann strukturierte, modulare Programme schreiben!
1 Gedanke zu „ARM64 Assembly Tutorial – Teil 3: Bedingungen, Schleifen und Kontrollfluss“
Die Kommentare sind geschlossen.