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
; 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
; 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
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öße | Multiplikator | Multiplikand (implizit) | Ergebnisspeicherung |
|---|---|---|---|
| 1 Byte | Beliebiges 8-Bit-Register oder Speicher | AL | AX = AL × Operand |
| 2 Byte | Beliebiges 16-Bit-Register oder Speicher | AX | DX:AX = AX × Operand |
| 4 Byte | Beliebiges 32-Bit-Register oder Speicher | EAX | EDX:EAX = EAX × Operand |
Beispiel
; 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
; 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öße | Dividend (implizit) | Quotient | Rest |
|---|---|---|---|
| 1 Byte | AX | AL | AH |
| 2 Byte | DX:AX | AX | DX |
| 4 Byte | EDX:EAX | EAX | EDX |
Beispiel
; 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
; 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
; 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
| Anweisung | Format | Funktion | Betroffene Flags |
|---|---|---|---|
| ADD | add dest, src | dest = dest + src | CF, ZF, SF, OF, PF |
| SUB | sub dest, src | dest = dest - src | CF, ZF, SF, OF, PF |
| INC | inc dest | dest = dest + 1 | ZF, SF, OF, PF (beeinflusst CF nicht) |
| DEC | dec dest | dest = dest - 1 | ZF, SF, OF, PF (beeinflusst CF nicht) |
| MUL | mul src | Unvorzeichenbehaftete Multiplikation | CF, OF |
| IMUL | imul src | Vorzeichenbehaftete Multiplikation | CF, OF |
| DIV | div src | Unvorzeichenbehaftete Division | Undefiniert (unbestimmt) |
| IDIV | idiv src | Vorzeichenbehaftete Division | Undefiniert (unbestimmt) |
| ADC | adc dest, src | dest = dest + src + CF | CF, ZF, SF, OF, PF |
| SBB | sbb dest, src | dest = dest - src - CF | CF, ZF, SF, OF, PF |
| NEG | neg dest | dest = -dest (negieren) | CF, ZF, SF, OF, PF |