EMZETT.
Login

Kurz: Ganzzahl-Register (rax …) können keine Kommazahlen rechnen. Dafür gibt es 16 XMM-Register (xmm0 bis xmm15, je 128 Bit) und die SSE2-Befehle. Für double (64 Bit) enden sie auf sd (scalar double):

Teil des Kurses Assembler (x86-64)

Kapitel 7 von 8 im Kurs Assembler (x86-64) (Abschnitt „Fortgeschritten“). Mit Fortschritt, Quiz und Zertifikat auf der Lernseite.

Fließkommazahlen mit SSE

Ganzzahl-Register (rax …) können keine Kommazahlen rechnen. Dafür gibt es 16 XMM-Register (xmm0 bis xmm15, je 128 Bit) und die SSE2-Befehle. Für double (64 Bit) enden sie auf sd (scalar double):

BefehlBedeutung
movsd xmm0, [x]double laden/speichern
addsd, subsd, mulsd, divsd+ − × ÷
sqrtsd xmm0, xmm1Quadratwurzel
cvtsi2sd xmm0, raxGanzzahl → double
cvttsd2si rax, xmm0double → Ganzzahl (abschneiden)
comisd xmm0, xmm1Vergleich (setzt ZF/CF, dann ja/jb)
section .data
    a    dq 3.5
    b    dq 2.0
    hun  dq 100.0
 
section .bss
    puffer resb 32
 
section .text
    global _start
 
_start:
    movsd xmm0, [a]
    addsd xmm0, [b]            ; 3.5 + 2.0 = 5.5
    mulsd xmm0, [hun]          ; * 100 = 550
    cvttsd2si rax, xmm0
    call ausgabe_zahl
 
    movsd xmm0, [a]
    mulsd xmm0, xmm0           ; 3.5² = 12.25
    mulsd xmm0, [hun]
    cvttsd2si rax, xmm0        ; 1225 (zwei Nachkommastellen als Ganzzahl)
    call ausgabe_zahl
 
    mov rax, 2
    cvtsi2sd xmm1, rax
    sqrtsd xmm1, xmm1          ; sqrt(2)
    movsd xmm2, [hun]
    mulsd xmm2, xmm2           ; 10000
    mulsd xmm1, xmm2
    cvttsd2si rax, xmm1        ; 14142 → sqrt(2) = 1.4142
    call ausgabe_zahl
 
    movsd xmm0, [a]
    movsd xmm1, [b]
    comisd xmm0, xmm1
    ja .groesser
    xor rax, rax
    jmp .ausgeben
.groesser:
    mov rax, 1                 ; 3.5 > 2.0
.ausgeben:
    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:

550
1225
14142
1

SIMD: mehrere Werte mit einem Befehl

SIMD (Single Instruction, Multiple Data) bearbeitet mehrere Werte gleichzeitig. Ein XMM-Register fasst z. B. vier float, zwei double oder vier 32-Bit-Ganzzahlen. Befehle mit ps/pd (packed) wirken auf alle Teile, padd* auf Ganzzahlen. Neuere Erweiterungen: AVX/AVX2 (256 Bit, ymm), AVX-512 (zmm).

section .data
    v1 dd 1, 2, 3, 4           ; vier 32-Bit-Ganzzahlen
    v2 dd 10, 20, 30, 40
 
section .bss
    puffer resb 32
    erg    resd 4
 
section .text
    global _start
 
_start:
    movdqu xmm0, [v1]
    movdqu xmm1, [v2]
    paddd xmm0, xmm1           ; vier Additionen auf einmal
    movdqu [erg], xmm0
 
    mov eax, [erg]
    call ausgabe_zahl          ; 11
    mov eax, [erg + 4]
    call ausgabe_zahl          ; 22
    mov eax, [erg + 8]
    call ausgabe_zahl          ; 33
    mov eax, [erg + 12]
    call ausgabe_zahl          ; 44
 
    movdqu xmm0, [v2]
    pslld xmm0, 1              ; alle vier Werte verdoppeln (Linksschieben)
    movdqu [erg], xmm0
    mov eax, [erg + 8]
    call ausgabe_zahl          ; 60
 
    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:

11
22
33
44
60

Compiler nutzen SIMD automatisch (Auto-Vektorisierung, gcc -O3 -march=native). Für Bilder, Audio, Spiele, Kryptografie und Machine Learning bringt es oft das 4- bis 16-fache Tempo.

Andere Architekturen

x86-64 ist nicht allein. Das Prinzip bleibt gleich: Register, Speicher, Sprünge, Systemaufrufe.

ArchitekturEinsatzBeispielbefehle
ARM64 (AArch64)Smartphones, Apple Silicon, Servermov x0, #5, add x0, x0, x1, ldr, str, bl, ret
RISC-Voffen, Forschung, Embeddedli a0, 5, add a0, a0, a1, lw, sw, jal
x86 (32 Bit)Altsystememov eax, 1, int 0x80
AVR / ARM Cortex-MMikrocontroller (Arduino, STM32)direkter Zugriff auf Pins

Ein Vergleich: Dieselbe Addition a + b.

x86-64:   mov rax, rdi          ; ARM64:   add x0, x0, x1     ; RISC-V:   add a0, a0, a1
          add rax, rsi          ;          ret                ;           ret
          ret

ARM und RISC-V sind Load/Store-Architekturen: Nur ldr/str bzw. lw/sw greifen auf Speicher zu, Rechenbefehle arbeiten ausschließlich mit Registern.

Merke

  • Fließkommazahlen rechnen mit XMM-Registern und SSE2 (addsd, mulsd, sqrtsd)
  • Umwandlung: cvtsi2sd (int → double), cvttsd2si (double → int)
  • SIMD (paddd, addps, AVX) bearbeitet mehrere Werte pro Befehl
  • Andere Architekturen (ARM64, RISC-V) folgen demselben Prinzip mit anderen Befehlen

Übungsaufgabe

Berechne den Mittelwert von 3, 4 und 8 als double und gib ihn mit zwei Nachkommastellen als Ganzzahl (mal 100) aus.

Quiz zur Selbstkontrolle

Weiter im Kurs

Zurück: Systemaufrufe, Eingabe und Werkzeuge

Weiter: Referenz und Spickzettel

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