Assemblersprache - Arithmetische Anweisungen

Arithmetische Anweisungen sind das Fundament mathematischer CPU-Operationen. Dieses Kapitel beschreibt Addition, Subtraktion, Multiplikation, Division und zugehörige Übertragsoperationen in der x86-Architektur im Detail.


ADD - Additionsanweisung

ADDAddiert den Quelloperanden zum Zieloperanden und speichert das Ergebnis im Zieloperanden.

Beispiel

; Dateipfad: add_demo.asm
; ADD-Anweisungsbeispiel: Berechne 100 + 200 + 300

section .data
    a dd 100
    b dd 200
    c dd 300
    sum dd 0

section .text
    global _start

_start:
    ; Methode 1: Register += Immediate
    mov eax, [a]                ; eax = 100
    add eax, 200                ; eax = 100 + 200 = 300

    ; Methode 2: Register += Register
    mov ebx, [b]                ; ebx = 200
    add eax, ebx                ; eax = 300 + 200 = 500

    ; Methode 3: Register += Speicher
    add eax, [c]                ; eax = 500 + 300 = 800

    ; Ergebnis speichern
    mov [sum], eax              ; sum = 800

    ; Auswirkung der Addition auf Flags
    mov eax, 0xFFFFFFFF         ; eax = größte 32-bit unsigned Zahl
    add eax, 1                  ; eax = 0 (Übertrag läuft über)
    ; CF = 1 (Übertrag erzeugt)
    ; ZF = 1 (Ergebnis ist 0)
    ; OF = 0 (kein Überlauf aus Sicht mit Vorzeichen)

    mov eax, 1
    mov ebx, 0
    int 0x80

SUB - Subtraktionsanweisung

SUBSubtrahiert den Quelloperanden vom Zieloperanden und speichert das Ergebnis im Zieloperanden.

Beispiel

; Dateipfad: sub_demo.asm
; SUB-Anweisungsbeispiel

section .data
    x dd 1000
    y dd 300

section .text
    global _start

_start:
    ; Einfache Subtraktion
    mov eax, [x]                ; eax = 1000
    sub eax, [y]                ; eax = 1000 - 300 = 700

    ; Auswirkung der Subtraktion auf Flags
    mov eax, 10
    sub eax, 20                 ; eax = -10 (d. h. 0xFFFFFFF6)
    ; CF = 1 (Borg erzeugt: 10 < 20)
    ; SF = 1 (Ergebnis ist negativ)
    ; ZF = 0 (Ergebnis ist ungleich 0)
    ; OF = 0 (kein Überlauf mit Vorzeichen)

    ; Sich selbst subtrahieren: oft zum Nullen verwendet
    mov eax, 12345
    sub eax, eax                ; eax = 0
    ; ZF = 1, CF = 0
    ; Dies ist eine klassische Methode, um ein Register zu nullen (effizienter als mov eax, 0)

    mov eax, 1
    mov ebx, 0
    int 0x80

sub eax, eaxist eine klassische Technik zum Nullen eines Registers; sie belegt nur 2 Byte, währendmov eax, 0belegt 5 Byte. Sie wird häufig in Szenarien verwendet, die extreme Größenoptimierung erfordern (wie Shellcode).


INC / DEC - Inkrementierungs-/Dekrementierungsanweisungen

Anweisungen zum Addieren und Subtrahieren von 1, die prägnanter sind als ADD/SUB:

Beispiel

; INC- und DEC-Beispiel

section .data
    counter dd 0

section .text
    global _start

_start:
    mov dword [counter], 0      ; counter = 0
    inc dword [counter]         ; counter = 1 (Speicheroperand)
    inc dword [counter]         ; counter = 2

    mov ecx, 10
    dec ecx                     ; ecx = 9
    dec ecx                     ; ecx = 8

    ; INC/DEC beeinflussen das CF-Flag nicht (dies ist ein wichtiger Unterschied zu ADD/SUB)
    ; Sie beeinflussen jedoch ZF, SF, OF, PF

    ; Verwendung von INC in einer Schleife
    mov ecx, 5
    mov eax, 0
loop_inc:
    inc eax                     ; eax wird jedes Mal um 1 erhöht
    loop loop_inc               ; 5 Mal wiederholen, eax ist am Ende = 5

    mov ebx, eax                ; Rückgabewert = 5
    mov eax, 1
    int 0x80

MUL - Unvorzeichenbehaftete Multiplikation

MULFührt eine unvorzeichenbehaftete Multiplikation durch. Die Regeln für die Multiplikation sind etwas speziell:

OperandengrößeMultiplikatorMultiplikand (implizit)Ergebnisspeicherung
1 ByteBeliebiges 8-Bit-Register oder SpeicherALAX = AL × Operand
2 ByteBeliebiges 16-Bit-Register oder SpeicherAXDX:AX = AX × Operand
4 ByteBeliebiges 32-Bit-Register oder SpeicherEAXEDX:EAX = EAX × Operand

Beispiel

; Dateipfad: mul_demo.asm
; MUL Beispiel für unvorzeichenbehaftete Multiplikation

section .data
    val1 dd 1000
    val2 dd 2000
    result_low dd 0
    result_high dd 0

section .text
    global _start

_start:
    ; 32-Bit-Multiplikation: EDX:EAX = EAX × Operand
    mov eax, [val1]             ; eax = 1000
    mul dword [val2]            ; edx:eax = 1000 × 2000 = 2.000.000
    ; Ergebnis = 2.000.000 = 0x001E8480
    ; EAX = 0x001E8480 (untere 32 Bit)
    ; EDX = 0x00000000 (obere 32 Bit, da das Ergebnis 32 Bit nicht überschritt)

    ; Demo zur Multiplikation großer Zahlen (Ergebnis überschreitet 32 Bit)
    mov eax, 0xFFFFFFFF         ; eax = 4.294.967.295
    mov ebx, 2                  ; ebx = 2
    mul ebx                     ; edx:eax = 0xFFFFFFFF × 2
    ; EAX = 0xFFFFFFFE
    ; EDX = 0x00000001 (obere 32 Bit)
    ; CF = 1 (Ergebnis überschreitet 32 Bit)

    ; Ergebnis speichern
    mov [result_low], eax
    mov [result_high], edx

    mov eax, 1
    mov ebx, 0
    int 0x80

IMUL – Vorzeichenbehaftete Multiplikation

IMULWird für die Multiplikation vorzeichenbehafteter Zahlen verwendet, mit drei Formen:

Beispiel

; Dateipfad: imul_demo.asm
; Beispiel für vorzeichenbehaftete Multiplikation mit IMUL

section .data
    a dd -100
    b dd 3

section .text
    global _start

_start:
    ; Ein-Operand-Form: identisch mit MUL
    mov eax, [a]                ; eax = -100
    imul dword [b]              ; edx:eax = -100 × 3 = -300
    ; EAX = -300(0xFFFFFED4)
    ; EDX = 0xFFFFFFFF (Vorzeichenerweiterung)

    ; Zwei-Operand-Form: reg = reg × Operand
    mov ebx, [a]                ; ebx = -100
    imul ebx, [b]               ; ebx = -100 × 3 = -300
    ; Das Ergebnis muss in 32 Bit passen

    ; Drei-Operand-Form: reg = Operand1 × Immediate
    imul ecx, [a], 5            ; ecx = -100 × 5 = -500

    mov eax, 1
    mov ebx, 0
    int 0x80

MULundIMULDer Hauptunterschied liegt in der Behandlung von Vorzeichen:MULWerden als vorzeichenlose Zahlen interpretiert,IMULWerden als vorzeichenbehaftete Zahlen interpretiert. Zum Beispiel ist 0xFFFFFFFF bei MUL gleich 4294967295 und bei IMUL gleich -1.


DIV – Vorzeichenlose Division

DIVFührt eine vorzeichenlose Division durch, die Regeln sind symmetrisch zu MUL:

DivisorengrößeDividend (implizit)QuotientRest
1 ByteAXALAH
2 ByteDX:AXAXDX
4 ByteEDX:EAXEAXEDX

Beispiel

; Dateipfad: div_demo.asm
; Beispiel für vorzeichenlose Division mit DIV

section .data
    dividend dd 1000
    divisor dd 7
    quotient dd 0
    remainder dd 0

section .text
    global _start

_start:
    ; 32-Bit-Division: edx:eax / Divisor
    ; Der Dividend muss zuerst auf EDX:EAX erweitert werden
    mov eax, [dividend]         ; eax = 1000
    mov edx, 0                  ; edx = 0 (obere 32 Bit löschen)
    div dword [divisor]         ; edx:eax / 7
    ; EAX = 142 (Quotient)
    ; EDX = 6 (Rest: 1000 = 142×7 + 6)

    mov [quotient], eax         ; quotient = 142
    mov [remainder], edx        ; remainder = 6

    ; Beispiel für Byteausschnitt-Division: 55 / 4
    mov ax, 55                  ; Dividend
    mov bl, 4                   ; Divisor
    div bl                      ; al = 13 (Quotient), ah = 3 (Rest)

    mov eax, 1
    mov ebx, 0
    int 0x80

Vergewissere dich vor der Division unbedingt,mov edx, 0oderxor edx, edxEDX zu löschen! Wenn EDX veraltete Daten enthält, ist der Dividend falsch. Dies ist der häufigste Divisionsfehler bei Anfängern.


IDIV – Vorzeichenbehaftete Division

IDIVWird für vorzeichenbehaftete Divisionen verwendet. Vor der Division musst du denCDQBefehl verwenden, um EAX in EDX:EAX vorzeichen zu erweitern:

Beispiel

; Beispiel für vorzeichenbehaftete Division mit IDIV

    ; Berechne -100 / 3
    mov eax, -100               ; eax = -100
    cdq                         ; Vorzeichenerweiterung: edx:eax = -100
                                ; cdq kopiert das Vorzeichenbit von eax in alle Bits von edx
    mov ebx, 3                  ; Divisor
    idiv ebx                    ; eax = -33 (Quotient), edx = -1 (Rest)
    ; Überprüfung: -100 = -33 × 3 + (-1)

ADC / SBB – Operationen mit Übertrag/Borg

Wird fürArithmetik mit großen Zahlen(Daten, die 32 Bit überschreiten) verwendet:

Beispiel

; Dateipfad: adc_sbb_demo.asm
; 64-Bit-Addition: Addition zweier 64-Bit-Zahlen

section .data
    ; 64-Bit-Zahl a = 0x00000001 FFFFFFFF
    a_low dd 0xFFFFFFFF
    a_high dd 0x00000001

    ; 64-Bit-Zahl b = 0x00000000 00000005
    b_low dd 0x00000005
    b_high dd 0x00000000

    ; Ergebnis
    result_low dd 0
    result_high dd 0

section .text
    global _start

_start:
    ; Untere 32 Bit addieren
    mov eax, [a_low]
    add eax, [b_low]            ; eax = 0xFFFFFFFF + 5 = 0x00000004
    ; CF = 1 (Übertrag aufgetreten!)
    mov [result_low], eax       ; result_low = 0x00000004

    ; Addiere die oberen 32 Bit mit Übertrag
    mov eax, [a_high]
    adc eax, [b_high]           ; adc = add + CF
    ; eax = 1 + 0 + 1(Übertrag) = 2
    mov [result_high], eax      ; result_high = 2

    ; Endergebnis (64 Bit): 0x00000002 00000004
    ; Überprüfung: 0x1FFFFFFF + 5 = 0x200000004

    ; SBB-Subtraktion ist ähnlich (mit Borg)
    mov eax, [a_low]
    sub eax, [b_low]            ; Subtrahiere die unteren 32 Bit
    mov [result_low], eax

    mov eax, [a_high]
    sbb eax, [b_high]           ; sbb = sub - CF

    mov eax, 1
    mov ebx, 0
    int 0x80

Schnellreferenztabelle für arithmetische Anweisungen

AnweisungFormatFunktionBetroffene Flags
ADDadd dest, srcdest = dest + srcCF, ZF, SF, OF, PF
SUBsub dest, srcdest = dest - srcCF, ZF, SF, OF, PF
INCinc destdest = dest + 1ZF, SF, OF, PF (beeinflusst CF nicht)
DECdec destdest = dest - 1ZF, SF, OF, PF (beeinflusst CF nicht)
MULmul srcUnvorzeichenbehaftete MultiplikationCF, OF
IMULimul srcVorzeichenbehaftete MultiplikationCF, OF
DIVdiv srcUnvorzeichenbehaftete DivisionUndefiniert (unbestimmt)
IDIVidiv srcVorzeichenbehaftete DivisionUndefiniert (unbestimmt)
ADCadc dest, srcdest = dest + src + CFCF, ZF, SF, OF, PF
SBBsbb dest, srcdest = dest - src - CFCF, ZF, SF, OF, PF
NEGneg destdest = -dest (negieren)CF, ZF, SF, OF, PF
Weitere Erweiterungen