Tutorial
Inlineassembler in FreeBASIC
von Volta | Seite 4 von 9 |
Rechenoperationen in Inlineassembler
Einschränkung: erst einmal keine Beachtung von überlauf und Vorzeichen.
Addition ADD
Dim As Long z1, z2, z3
z1 = 123456789
z2 = 234567890
asm
mov eax, [z1] 'eax = [z1]
mov ebx, [z2] 'ebx = [z2]
add eax, ebx 'eax + ebx
mov [z3], eax '[z3] = eax
End asm
Print z1, z2, z3
sleep
Eine klassische Operation nach dem EVA - Prinzip:
- (E) ingabe ; z1 und z2 in die Register eax, ebx holen,
- (V) erarbeitung ; eax + ebx berechnen,
- (A) usgabe ; Summe aus eax in z3 speichern.
Trick:
Dim As Long z1, z2, z3
z1 = 123456789
z2 = 234567890
asm
mov eax, [z1]
mov ebx, [z2]
lea eax, [eax + ebx]
mov [z3], eax
End asm
Print z1, z2, z3
sleep
Sieht auf den ersten Blick nicht wie eine Addition aus, ist aber eine.
Hier wird der LEA Befehl zur Addition benutzt. Das hat manchmal einen kleinen Geschwindigkeitsvorteil, da dieser Befehl nur mit den Registern des Prozessors arbeitet.
Eine Konstante dürfte noch zusätzlich addiert werden (z.B. lea eax, [eax + ebx + 64])
Variante zum ersten Beispiel:
Das Ergebnis soll in z2 berechnet werden, vergleichbar mit freeBASIC z2 += z1.
Dim As Long z1, z2
z1 = 123456789
z2 = 234567890
asm
mov eax, [z1]
add [z2], eax
End asm
Print z1, z2
sleep
Genau wie beim MOV - Befehl dürfen auch beim ADD - Befehl nicht beide Operanden auf eine Adresse zeigen, deshalb wird hier das eax - Register mitbenutzt.
Subtraktion SUB
Klassische Version:
Dim As Long z1, z2, z3
z1 = 123456789
z2 = 234567890
asm
mov eax, [z1] 'eax = [z1]
mov ebx, [z2] 'ebx = [z2]
sub eax, ebx 'eax - ebx
mov [z3], eax '[z3] = eax
End asm
Print z1, z2, z3
sleep
Wenn man eine größere Zahl von einer kleineren Zahl abzieht dann kommt ein negatives Ergebnis, aber nur weil wir hier mit vorzeichenbehafteten [url=ref:321;Integer[/url] - Variablen (z1, z2, z3) arbeiten!
Ändere dies:
Dim As ULong z1, z2, z3
und das Ergebnis sieht anders aus.
Mal was Neues:
Dim As Byte z3
asm
jmp Label3 'Springe zu dem Befehl der nach Label3: steht
L1: .Byte 234 'L1: wird wie eine Variable in FB
'behandelt die den Wert 234 enthält
L2: .Byte 246
Label3:
mov al, [L1] 'Hier wieder klassisch
mov bl, [L2] 'nur mit Byte
sub al, bl
mov [z3], al
End asm
Print z3
sleep
Label setzen
Ein Label (oder Marke) ist durch einen Doppelpunkt am Ende gekennzeichnet, dann wird dem Ausdruck eine Adresse im Speicher zugewiesen.
An dieser Stelle befindet sich sozusagen ein Fixpunkt, der entweder im Programmablauf liegt und als Ansprungmarke dient, oder eine Stelle kennzeichnet an der Daten abgelegt wurden.
Im Beispiel werden beide Arten gezeigt: Label3 ist eine Sprungmarke, L1 und L2 kennzeichnen Daten.
Wie war das noch, ein Prozessor kann eigentlich nicht subtrahieren?
Er bildet das Zweierkomplement und addiert dann?
Versucht wir es mal:
Dim As Short z3
asm
jmp Label3
L1: .short 2345
L2: .short 2467
Label3:
mov ax, [L1]
mov bx, [L2]
'Zweierkomplement von bx bilden
Not bx 'negieren von bx
inc bx 'bx + 1
add ax, bx 'dann addieren
mov [z3], ax
End asm
Print z3
sleep
Na also, geht noch!
Die Subtraktion wird auf eine Addition zurückgeführt.
Da ist noch ein neuer Befehl enthalten INC, damit kann ein Register um den Wert 1 erhöht werden. Der entsprechende Befehl für Register - 1 ist DEC. Beide werden bei der Erstellung von Zählschleifen häufig eingesetzt.
Multiplikation MUL
Dim As ULong z1, z2, z3, z4
Dim zlang As UlongInt
z1 = 207700
z2 = 56012
asm
mov ebx, [z2] 'ebx <- [z2]
mov eax, [z1] 'eax <- [z1]
'cdq 'Vorzeichenerweiterung auf edx - Register
xor edx, edx 'edx <- 0
mul ebx 'edx:eax <- eax * ebx
mov [z3], eax '[z3] <- eax
mov [z4], edx '[z4] <- edx ; übertrag
mov [zlang], eax '[zlang ; xxxxLLLL] <- eax
mov [zlang + 4], edx '[zlang ; HHHHxxxx] <- edx
End asm
Print z4, z3
Print zlang
sleep
Viel zu aufwändig der Asm - Teil? Sonst steht da nur 'MUL reg' und fertig!
Na ja, wenn ich sicher bin 32 Bit, die Registergröße, nicht zu überschreiten mach ich das auch so. Wenn ich das aber nicht von vornherein festlegen kann, dann ist mir dieser Aufwand lieber, denn ich bekomme ein genaues Ergebnis.
Trick:
Dim As Long z3
asm
mov eax, 2077
shl eax,1 ' multiplizieren mit 2
mov [z3], eax
End asm
Print z3
sleep
SHL reg, n ist ein Befehl der alle Bitwerte des Registers (reg) um die Anzahl (n) Stellen nach links versetzt (schiebt)und rechts eine 0 einfügt.
Wenn wir das in unserem gewohnten Dezimalsystem machen, sprechen wir davon "das Komma eine Stelle nach rechts zu schieben", wir multiplizieren mit 10.
Im Binärsystem multiplizieren wir mit der Basis 2. D.h. jedes linksschieben entspricht einer Multiplikation mit 2, jedes rechtsschieben (SHR reg, n) entspricht einer Division durch 2.
Division DIV
Bei der Division gibt es nicht die Überlaufprobleme wie bei der Multiplikation.
Trotzdem wird wieder das edx - Register mitbenutzt!
Dim As integer z1, z2, z3, z4
z1 = 207700
z2 = 560
asm
mov eax, [z1]
mov ebx, [z2]
xor edx, edx
div ebx ' dividieren
mov [z3], eax '
mov [z4], edx ' Rest ( z1 Mod Z2)
End asm
Print z3, "Rest: ";z4
sleep
Bei der Integerdivision (Ganzzahldivision mit Rest) wird das Ergebnis in das eax - Register und der verbleibende Rest in das edx - Register gespeichert. Der Rest im edx - Register hat das gleiche Ergebnis wie die MOD-Operation in freeBASIC.
Zusätzliche Informationen und Funktionen | |||||||
---|---|---|---|---|---|---|---|
|