Assemblersprache - Bedingte Verzweigung
Die bedingte Verzweigung ist der Grundstein der Programmsteuerungslogik. Assemblersprache implementiert Verzweigungslogik wie if-else, switch usw. durch Vergleichsbefehle und bedingte Sprungbefehle.
CMP - Vergleichsbefehl
CMPFührt eine Subtraktionsoperation an zwei Operanden aus (Ziel - Quelle), speichert das Ergebnis jedoch nicht, sondern aktualisiert nur die Flags.
Im WesentlichenCMP dest, srcÄquivalent zuSUB dest, srcVerwirft jedoch das Berechnungsergebnis.
Beispiel
section .text
global _start
_start:
mov eax, 10
cmp eax, 10 ; eax == 10?
; ZF = 1 (gleich, Ergebnis ist null)
; CF = 0 (kein Übertrag)
; SF = 0 (Ergebnis nicht negativ)
mov eax, 5
cmp eax, 10 ; eax == 10?
; ZF = 0 (ungleich, Ergebnis ungleich null)
; CF = 1 (Übertrag: 5 < 10)
mov eax, 20
cmp eax, 10 ; eax == 10?
; ZF = 0 (ungleich)
; CF = 0 (kein Übertrag: 20 >= 10)
; SF = 0 (Ergebnis nicht negativ: 10 > 0)
mov eax, 1
mov ebx, 0
int 0x80
Bedingte Sprungbefehle
Bedingte Sprungbefehle bestimmen basierend auf dem Zustand der Flags, ob gesprungen werden soll. Wenn die Bedingung wahr ist, springe zur Zielmarke; andernfalls fahre mit der Ausführung des nächsten Befehls fort.
| Anweisung | Bedeutung | Geprüfte Flags | Anwendungsfall |
|---|---|---|---|
| JE / JZ | Springe, wenn gleich / null | ZF = 1 | cmp a, bÜberprüfe a == b nach CMP |
| JNE / JNZ | Springe, wenn ungleich / nicht null | ZF = 0 | cmp a, bÜberprüfe a != b nach CMP |
| JG / JNLE | Springe, wenn größer (mit Vorzeichen) | ZF=0 und SF=OF | Zahlen mit Vorzeichen a > b |
| JGE / JNL | Springe, wenn größer oder gleich (mit Vorzeichen) | SF = OF | Zahlen mit Vorzeichen a >= b |
| JL / JNGE | Springe, wenn kleiner (mit Vorzeichen) | SF != OF | Zahl mit Vorzeichen a < b |
| JLE / JNG | Springe, wenn kleiner oder gleich (mit Vorzeichen) | ZF=1 oder SF!=OF | Zahl mit Vorzeichen a <= b |
| JA / JNBE | Springe, wenn größer (ohne Vorzeichen) | CF=0 und ZF=0 | Zahl ohne Vorzeichen a > b |
| JAE / JNB | Springe, wenn größer oder gleich (ohne Vorzeichen) | CF = 0 | Zahl ohne Vorzeichen a >= b |
| JB / JNAE | Springe, wenn kleiner (ohne Vorzeichen) | CF = 1 | Zahl ohne Vorzeichen a < b |
| JBE / JNA | Springe, wenn kleiner oder gleich (ohne Vorzeichen) | CF=1 oder ZF=1 | Zahl ohne Vorzeichen a <= b |
Many instructions have two aliases (such as JE and JZ), which are exactly the same at the machine code level. Which one to use depends on the context: use JE/JNE after comparisons, and JZ/JNZ after checking operation results. This improves code readability.
Single-Branch IF Structure
Beispiel
; Implementation: if (x > 10) x = 10;
section .data
x dd 15 ; Test value
limit dd 10
section .text
global _start
_start:
mov eax, [x] ; Load x into eax
cmp eax, [limit] ; x > 10 ?
jle skip_update ; If x <= 10, skip update
mov dword [x], 10 ; x = 10
skip_update:
; Program continues... (here x is already 10)
mov eax, 1
mov ebx, 0
int 0x80
IF-ELSE Double-Branch Structure
Beispiel
; Implementation: if (score >= 60) grade = 'P' else grade = 'F'
section .data
score dd 75 ; Exam score
grade db 0 ; Grade
PASS_SCORE equ 60
section .text
global _start
_start:
mov eax, [score] ; Load score
cmp eax, PASS_SCORE ; score >= 60 ?
jge pass_label ; If >= 60, jump to pass
; else branch: fail
mov byte [grade], 'F' ; grade = 'F'
jmp end_if ; skip if branch
pass_label:
; if branch: pass
mov byte [grade], 'P' ; grade = 'P'
end_if:
; grade variable is now set
; output grade
mov eax, 4
mov ebx, 1
mov ecx, grade
mov edx, 1
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
Run result:
$ nasm -f elf32 if_else_demo.asm -o if_else_demo.o $ ld -m elf_i386 if_else_demo.o -o if_else_demo $ ./if_else_demo P
IF-ELSE IF-ELSE Multi-Branch Structure
Below uses a score grading system as an example to show the flow of multi-branch decision:
Beispiel
; Score grading: >=90 -> A, >=80 -> B, >=70 -> C, >=60 -> D, <60 -> F
section .data
score dd 85
result db 0
newline db 0xA
section .text
global _start
_start:
mov eax, [score] ; Load score
; Check >= 90
cmp eax, 90
jl check_80 ; If < 90, continue checking
mov byte [result], 'A'
jmp print_result
check_80:
cmp eax, 80
jl check_70
mov byte [result], 'B'
jmp print_result
check_70:
cmp eax, 70
jl check_60
mov byte [result], 'C'
jmp print_result
check_60:
cmp eax, 60
jl fail_label
mov byte [result], 'D'
jmp print_result
fail_label:
mov byte [result], 'F'
print_result:
; Output grade
mov eax, 4
mov ebx, 1
mov ecx, result
mov edx, 1
int 0x80
; Output newline
mov eax, 4
mov ebx, 1
mov ecx, newline
mov edx, 1
int 0x80
mov eax, 1
mov ebx, 0
int 0x80
TEST - Non-Destructive Test Instruction
TESTPerforms bitwise AND but does not save the result, only updates flags.
TESTOften used to check whether a specific bit is 1, or whether a register is 0.
Beispiel
; Check if eax is 0 (more efficient than CMP eax, 0)
test eax, eax ; eax & eax = eax, only updates ZF
jz eax_is_zero ; If ZF=1, then eax=0
; Check a specific bit
test al, 0x01 ; Check if bit0 is 1
jnz bit0_is_set ; If bit0=1, jump
; Check multiple bits
test al, 0x03 ; Check if at least one of bit0 and bit1 is 1
jnz some_bit_set
SETcc – Bedingte Setzanweisung
Anstatt zu springen, setzt das Zielbyte basierend auf der Bedingung auf 1 oder 0:
Beispiel
; Speichere das Ergebnis von a > b in al
mov eax, 10
cmp eax, 5 ; 10 > 5 ?
setg al ; al = 1 (größer-als trifft zu)
; Wenn eax = 3, dann al = 0
; Andere SETcc-Anweisungen:
; sete / setz -> gleich/null
; setne / setnz -> ungleich/nicht null
; setl -> kleiner als (mit Vorzeichen)
; setb -> kleiner als (ohne Vorzeichen)
; setg -> größer als (mit Vorzeichen)
; seta -> größer als (ohne Vorzeichen)
; Vollständiges Beispiel: Gerade/Ungerade und Positiv/Negativ bestimmen
Beispiel
; Bestimme, ob eine Zahl gerade/ungerade, positiv/negativ ist
section .data
number dd -42
msg_even db 'Even', 0xA
msg_even_len equ $ - msg_even
msg_odd db 'Odd', 0xA
msg_odd_len equ $ - msg_odd
msg_pos db 'Positive', 0xA
msg_pos_len equ $ - msg_pos
msg_neg db 'Negative', 0xA
msg_neg_len equ $ - msg_neg
msg_zero db 'Zero', 0xA
msg_zero_len equ $ - msg_zero
section .text
global _start
_start:
mov eax, [number]
; Prüfe, ob Null
cmp eax, 0
jne check_sign
; ist Null
mov eax, 4
mov ebx, 1
mov ecx, msg_zero
mov edx, msg_zero_len
int 0x80
jmp exit
check_sign:
; Prüfe positiv/negativ
cmp eax, 0
jg is_positive ; eax > 0
; negativ
mov eax, 4
mov ebx, 1
mov ecx, msg_neg
mov edx, msg_neg_len
int 0x80
jmp check_parity
is_positive:
; positiv
mov eax, 4
mov ebx, 1
mov ecx, msg_pos
mov edx, msg_pos_len
int 0x80
check_parity:
; Bestimme gerade/ungerade (muss nur das unterste Bit prüfen)
mov eax, [number]
test eax, 1 ; Prüfe bit0
jnz is_odd
; gerade
mov eax, 4
mov ebx, 1
mov ecx, msg_even
mov edx, msg_even_len
int 0x80
jmp exit
is_odd:
; ungerade
mov eax, 4
mov ebx, 1
mov ecx, msg_odd
mov edx, msg_odd_len
int 0x80
exit:
mov eax, 1
mov ebx, 0
int 0x80
Weitere ErweiterungenBedingte Sprunganweisungen können nur zu Sprungmarken innerhalb des aktuellen Codesegments springen; der Sprungbereich ist normalerweise auf etwa 128 Bytes (kurzer Sprung) bis 2 GB (naher Sprung) begrenzt. NASM wählt automatisch die passende Sprungcodierung.