EMZETT.
Login

Kurz: cmp a, b rechnet a - b nur für die Flags. Danach springt ein bedingter Sprung, wenn die Bedingung stimmt, sonst läuft das Programm einfach weiter:

Teil des Kurses Assembler (x86-64)

Kapitel 3 von 8 im Kurs Assembler (x86-64). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

cmp und bedingte Sprünge

cmp a, b rechnet a - b nur für die Flags. Danach springt ein bedingter Sprung, wenn die Bedingung stimmt, sonst läuft das Programm einfach weiter:

SprungBedingungBedeutung
je / jzZF = 1gleich / null
jne / jnzZF = 0ungleich
jl / jgvorzeichenbehaftetkleiner / größer
jle / jgevorzeichenbehaftetkleiner-gleich / größer-gleich
jb / javorzeichenlosbelow / above
jmpimmerunbedingter Sprung
section .bss
    puffer resb 32
 
section .text
    global _start
 
_start:
    mov rax, 7
    cmp rax, 10
    jl .kleiner
    mov rbx, 0
    jmp .weiter
.kleiner:
    mov rbx, 1            ; rax ist kleiner als 10
.weiter:
    mov rax, rbx
    call ausgabe_zahl
 
    ; Maximum von zwei Zahlen
    mov rax, 15
    mov rbx, 42
    cmp rax, rbx
    jge .rax_ist_max
    mov rax, rbx          ; rbx ist größer
.rax_ist_max:
    call ausgabe_zahl
 
    ; Betrag (abs)
    mov rax, -17
    test rax, rax         ; setzt Flags wie "and rax, rax"
    jns .positiv
    neg rax
.positiv:
    call ausgabe_zahl
 
    ; gerade oder ungerade?
    mov rax, 27
    test rax, 1           ; unterstes Bit
    jz .gerade
    mov rax, 1            ; ungerade
    jmp .fertig
.gerade:
    mov rax, 0
.fertig:
    call ausgabe_zahl
 
    mov rax, 60
    xor rdi, rdi
    syscall
 
; --- Hilfsroutine: gibt die Zahl in RAX dezimal aus (mit Zeilenumbruch), alle Register bleiben erhalten ---
ausgabe_zahl:
    push rax
    push rbx
    push rcx
    push rdx
    push rsi
    push rdi
    mov rcx, puffer + 20        ; Ende des Puffers
    mov byte [rcx], 10          ; Zeilenumbruch ans Ende
    mov rbx, 10
.schleife:
    xor rdx, rdx
    div rbx                     ; RAX = RAX / 10, RDX = Rest
    add dl, '0'                 ; Ziffer in ASCII umwandeln
    dec rcx
    mov [rcx], dl
    test rax, rax
    jnz .schleife
    mov rax, 1                  ; write
    mov rdi, 1
    mov rsi, rcx
    lea rdx, [puffer + 21]
    sub rdx, rcx
    syscall
    pop rdi
    pop rsi
    pop rdx
    pop rcx
    pop rbx
    pop rax
    ret

Ausgabe:

1
42
17
1

Die Namen mit Punkt (.kleiner) sind lokale Labels, die zum letzten globalen Label gehören. So kannst du .schleife mehrfach in verschiedenen Routinen verwenden.

Schleifen

Eine Schleife ist ein Zähler, eine Marke am Anfang und ein bedingter Sprung zurück:

section .bss
    puffer resb 32
 
section .text
    global _start
 
_start:
    ; Zählen von 1 bis 5
    mov rcx, 1
.zaehlen:
    mov rax, rcx
    call ausgabe_zahl
    inc rcx
    cmp rcx, 5
    jle .zaehlen
 
    ; Summe 1 bis 100
    xor rax, rax
    mov rcx, 100
.summe:
    add rax, rcx
    dec rcx
    jnz .summe             ; solange rcx nicht 0
    call ausgabe_zahl
 
    ; Fakultät von 10
    mov rax, 1
    mov rcx, 10
.fak:
    imul rax, rcx
    loop .fak              ; loop: rcx verringern, springen solange rcx != 0
    call ausgabe_zahl
 
    ; Fibonacci: die ersten 10 Zahlen
    mov rax, 0
    mov rbx, 1
    mov rcx, 10
.fib:
    push rax
    call ausgabe_zahl
    pop rax
    mov rdx, rax
    add rdx, rbx
    mov rax, rbx
    mov rbx, rdx
    dec rcx
    jnz .fib
 
    mov rax, 60
    xor rdi, rdi
    syscall
 
; --- Hilfsroutine: gibt die Zahl in RAX dezimal aus (mit Zeilenumbruch), alle Register bleiben erhalten ---
ausgabe_zahl:
    push rax
    push rbx
    push rcx
    push rdx
    push rsi
    push rdi
    mov rcx, puffer + 20        ; Ende des Puffers
    mov byte [rcx], 10          ; Zeilenumbruch ans Ende
    mov rbx, 10
.schleife:
    xor rdx, rdx
    div rbx                     ; RAX = RAX / 10, RDX = Rest
    add dl, '0'                 ; Ziffer in ASCII umwandeln
    dec rcx
    mov [rcx], dl
    test rax, rax
    jnz .schleife
    mov rax, 1                  ; write
    mov rdi, 1
    mov rsi, rcx
    lea rdx, [puffer + 21]
    sub rdx, rcx
    syscall
    pop rdi
    pop rsi
    pop rdx
    pop rcx
    pop rbx
    pop rax
    ret

Ausgabe:

1
2
3
4
5
5050
3628800
0
1
1
2
3
5
8
13
21
34

Hinweis

loop ist kompakt, aber auf modernen Prozessoren langsamer als dec rcx + jnz. Compiler erzeugen deshalb meist die zweite Form.

Verschachtelte Schleifen: Primzahlen

section .bss
    puffer resb 32
 
section .text
    global _start
 
_start:
    mov r8, 2                 ; Kandidat
.kandidat:
    mov r9, 2                 ; Teiler
.teiler:
    mov rax, r9
    imul rax, r9
    cmp rax, r8               ; teiler^2 > kandidat? dann prim
    jg .ist_prim
    mov rax, r8
    xor rdx, rdx
    div r9
    test rdx, rdx
    jz .naechster             ; Rest 0 → keine Primzahl
    inc r9
    jmp .teiler
.ist_prim:
    mov rax, r8
    call ausgabe_zahl
.naechster:
    inc r8
    cmp r8, 40
    jle .kandidat
 
    mov rax, 60
    xor rdi, rdi
    syscall
 
; --- Hilfsroutine: gibt die Zahl in RAX dezimal aus (mit Zeilenumbruch), alle Register bleiben erhalten ---
ausgabe_zahl:
    push rax
    push rbx
    push rcx
    push rdx
    push rsi
    push rdi
    mov rcx, puffer + 20        ; Ende des Puffers
    mov byte [rcx], 10          ; Zeilenumbruch ans Ende
    mov rbx, 10
.schleife:
    xor rdx, rdx
    div rbx                     ; RAX = RAX / 10, RDX = Rest
    add dl, '0'                 ; Ziffer in ASCII umwandeln
    dec rcx
    mov [rcx], dl
    test rax, rax
    jnz .schleife
    mov rax, 1                  ; write
    mov rdi, 1
    mov rsi, rcx
    lea rdx, [puffer + 21]
    sub rdx, rcx
    syscall
    pop rdi
    pop rsi
    pop rdx
    pop rcx
    pop rbx
    pop rax
    ret

Ausgabe:

2
3
5
7
11
13
17
19
23
29
31
37

Merke

  • cmp vergleicht, test prüft Bits; danach je/jne/jl/jg/jle/jge (vorzeichenbehaftet), jb/ja (vorzeichenlos)
  • jmp springt immer; Labels markieren Ziele, .name sind lokal
  • Schleife: Zähler, Label, dec + jnz (oder loop)
  • if/else und while sind in Assembler nur Sprungmuster

Übungsaufgabe

Zähle die Zahlen von 1 bis 100 durch und gib nur die durch 7 teilbaren aus.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Register und Rechnen

Weiter: Speicher, Arrays und Zeichenketten

Alle Kapitel: Assembler (x86-64) im Überblick