Assemblercode

Ein Assembler übersetzt menschenlesbare Gedächtnishilfen in direkt ausführbaren Maschinencode. Dabei wird jeder Befehl einer konkreten Prozessorarchitektur zugeordnet. So können mithilfe von Befehlen wie MOV, ADD oder JMP Operationen auf Registern und im Speicher ausgeführt werden. Im Folgenden finden sich verschiedene Beispiele, die den praktischen Einsatz von Assemblersprache aufzeigen.

Beispiel 1: Funktion, die das Maximum aus drei Zahlen liefert

; x86-64 GNU Assembler Syntax
; Parameter in rdi, rsi, rdx
; Rückgabewert über rax

global maxofthree
section .text

maxofthree:
    mov rax, rdi       ; rax ← x
    cmp rsi, rax       ; vergleiche y mit aktuellem max
    cmovl rax, rsi     ; falls y größer ist, rax ← y
    cmp rdx, rax       ; vergleiche z mit aktuellem max
    cmovl rax, rdx     ; falls z größer ist, rax ← z
    ret                ; rax enthält das Maximum

Diese Routine nimmt drei int64_t-Werte entgegen und gibt den größten Wert zurück[1]. Ein entsprechender Aufruf aus C setzt die Parameter in rdi, rsi und rdx und erwartet das Ergebnis in rax.

Beispiel 2: Kleine arithmetische Berechnungen

; x86-64 Linux Syntax
; Berechnet (RDI + RSI) * 4 und speichert das Ergebnis in RAX

global compute
section .text

compute:
    mov rax, rdi       ; rax ← erster Parameter
    add rax, rsi       ; rax ← rax + zweiter Parameter
    shl rax, 2         ; rax ← rax << 2 (Multiplikation mit 4)
    ret

Hier wird zunächst ein Wert aus rdi geholt, mit rsi addiert und anschließend mit dem Befehl shl (Shift Left) vervierfacht. Dieser Code verdeutlicht, wie direkt Registerinhalte manipuliert werden können.

Beispiel 3: Einfache Datenzugriffe im Speicher

; Kopiert einen 32-Bit Wert aus der Speicheradresse [RDI] in EAX
; Zum Schluss erhöht es den Wert in EAX um 1

global incrementMemory
section .text

incrementMemory:
    mov eax, [rdi]   ; eax ← Wert an Speicheradresse rdi
    inc eax          ; eax ← eax + 1
    mov [rdi], eax   ; aktualisiere Speicheradresse mit neuem Wert
    ret

Die Instruktion mov eax, [rdi] liest 4 Bytes (32 Bit) aus dem Speicher in eax, während mov [rdi], eax den Wert wieder an dieselbe Stelle im Speicher schreibt.

Beispiel 4: Schleife mit Dekrement und bedingtem Sprung

; Summiert mehrere Double-Werte aus einem Array (64-Bit Gleitkommazahlen).
; Param:
;   rdi: Zeiger auf das Start-Array
;   rsi: Anzahl der Elemente
; Rückgabewert in xmm0

global sumOfDoubles
section .text

sumOfDoubles:
    xorpd xmm0, xmm0       ; xmm0 ← 0.0 (Initialisierung)
    cmp rsi, 0             ; wenn keine Elemente, überspringen
    je .done

.loop:
    addsd xmm0, [rdi]      ; double-Wert an [rdi] zu xmm0 addieren
    add rdi, 8             ; Zeiger um 8 Bytes erhöhen (nächstes Double)
    dec rsi                ; Anzahl der Elemente dekrementieren
    jnz .loop              ; solange rsi != 0, weitermachen

.done:
    ret

Die Schleife addiert fortlaufend Double-Werte aus dem Speicher, bis alle Elemente verarbeitet sind. Durch jnz wird gesprungen, solange das Zero-Flag den Wert 0 nicht anzeigt, also rsi ungleich 0 ist.

Assembler und Maschinencode

Ein Assembler ordnet jedem Befehl ein maschinenspezifisches Codewort zu und erzeugt daraus ein lauffähiges Objektprogramm. Diese geringe Abstraktionsebene ermöglicht eine präzise Steuerung der Hardware. Praktisch wird ein reines Schreiben von Maschinencode vermieden, da Fehlerquellen hoch sind und Assemblersprache deutlich übersichtlicher ist.

Ähnliche Beiträge

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert