Gleitkommaoperationen: Unterschied zwischen den Versionen
KKeine Bearbeitungszusammenfassung |
KKeine Bearbeitungszusammenfassung |
||
| Zeile 133: | Zeile 133: | ||
=== Addition (fadd) === | === Addition (fadd) === | ||
<syntaxhighlight lang="asm"> | |||
.section .data | .section .data | ||
var1: .double 3.14 | var1: .double 3.14 | ||
| Zeile 153: | Zeile 153: | ||
mov x0, #0 | mov x0, #0 | ||
svc 0 | svc 0 | ||
</syntaxhighlight> | |||
=== Subtraktion (fsub) === | === Subtraktion (fsub) === | ||
<syntaxhighlight lang="asm"> | |||
.section .data | .section .data | ||
var1: .double 3.14 | var1: .double 3.14 | ||
| Zeile 176: | Zeile 176: | ||
mov x0, #0 | mov x0, #0 | ||
svc 0 | svc 0 | ||
</syntaxhighlight> | |||
=== Multiplikation (fmul) === | === Multiplikation (fmul) === | ||
<syntaxhighlight lang="asm"> | |||
.section .data | .section .data | ||
var1: .double 3.14 | var1: .double 3.14 | ||
| Zeile 199: | Zeile 199: | ||
mov x0, #0 | mov x0, #0 | ||
svc 0 | svc 0 | ||
</syntaxhighlight> | |||
=== Division (fdiv) === | === Division (fdiv) === | ||
<syntaxhighlight lang="asm"> | |||
.section .data | .section .data | ||
var1: .double 3.14 | var1: .double 3.14 | ||
| Zeile 222: | Zeile 222: | ||
mov x0, #0 | mov x0, #0 | ||
svc 0 | svc 0 | ||
</syntaxhighlight> | |||
=== Konvertierung von Gleitkommazahlen === | === Konvertierung von Gleitkommazahlen === | ||
==== Ganzzahl zu Gleitkommazahl (scvtf / ucvtf) ==== | ==== Ganzzahl zu Gleitkommazahl (scvtf / ucvtf) ==== | ||
<syntaxhighlight lang="asm"> | |||
.section .data | .section .data | ||
int_val: .word 10 | int_val: .word 10 | ||
| Zeile 243: | Zeile 243: | ||
mov x0, #0 | mov x0, #0 | ||
svc 0 | svc 0 | ||
</syntaxhighlight> | |||
==== Gleitkommazahl zu Ganzzahl (fcvtzs / fcvtzu) ==== | ==== Gleitkommazahl zu Ganzzahl (fcvtzs / fcvtzu) ==== | ||
<syntaxhighlight lang="asm"> | |||
.section .data | .section .data | ||
float_val: .double 3.14 | float_val: .double 3.14 | ||
| Zeile 263: | Zeile 263: | ||
mov x0, #0 | mov x0, #0 | ||
svc 0 | svc 0 | ||
</syntaxhighlight> | |||
=== Vergleich von Gleitkommazahlen und bedingte Sprungbefehle === | === Vergleich von Gleitkommazahlen und bedingte Sprungbefehle === | ||
==== Vergleich von Gleitkommazahlen (fcmpe / fcsel) ==== | ==== Vergleich von Gleitkommazahlen (fcmpe / fcsel) ==== | ||
<syntaxhighlight lang="asm"> | |||
.section .data | .section .data | ||
var1: .double 3.14 | var1: .double 3.14 | ||
| Zeile 298: | Zeile 298: | ||
mov x0, #0 | mov x0, #0 | ||
svc 0 | svc 0 | ||
</syntaxhighlight> | |||
'''Wichtiger Hinweis:''' | '''Wichtiger Hinweis:''' | ||
fcmpe: Vergleich von Gleitkommazahlen nach IEEE 754. | fcmpe: Vergleich von Gleitkommazahlen nach IEEE 754. | ||
Version vom 7. April 2025, 12:41 Uhr
In diesem Kapitel werden wir uns mit Gleitkommaoperationen im ARM64-Assembler beschäftigen. Die Schwerpunkte liegen auf den FPU-Registern (Floating Point Unit), einem Überblick über die Register und deren Verwendung in Funktionen. Ebenso werden wichtige Hinweise zur Verwendung der Register für Gleitkommaoperationen gegeben.
FPU-Register: Überblick
Unter ARM64 haben wir eine dedizierte Einheit für Gleitkommaoperationen, die sogenannte FPU (Floating Point Unit). Diese Einheit verwendet spezifische Register, um Gleitkommaoperationen auszuführen.
Registerüberblick
- s0 - s31: Einzelpräzisions-Gleitkomma-Register (32-Bit)
- d0 - d31: Doppelpräzisions-Gleitkomma-Register (64-Bit)
- q0 - q31: Vektorregister (128-Bit)
Diese Register werden für verschiedene Arten von Gleitkommaoperationen und SIMD (Single Instruction, Multiple Data) verwendet. Hier konzentrieren wir uns hauptsächlich auf die Register d0 bis d31 für Doppelpräzisions-Gleitkommaoperationen.
Verwendung der FPU-Register in Funktionen
Um Gleitkommaoperationen in ARM64-Assembler durchzuführen, sind bestimmte Anweisungen und Register zu beachten. Im Folgenden finden Sie grundlegende Beispiele und Best Practices für die Durchführung von Gleitkommaoperationen.
Beispiel: Gleitkommaaddition
.section .data
var1: .double 3.14
var2: .double 1.618
.section .text
.global _start
_start:
// Lade Gleitkommawerte in d-Register
ldr x0, =var1
ldr d0, [x0]
ldr x1, =var2
ldr d1, [x1]
// Führe die Gleitkommaaddition durch
fadd d2, d0, d1 // d2 = d0 + d1
// Beispiel: Rückgabe des Ergebnisses mit einem Systemaufruf
// (zur Vereinfachung hier nicht gezeigt, da Gleitkomma nicht direkt unterstützt wird)
// Exit system call
mov x8, #93 // syscall number for exit
mov x0, #0 // exit code
svc 0
Hinweise zur Verwendung von FPU-Registern
- Laden und Speichern von Gleitkommawerten: Verwendung von Load/Store-Instruktionen wie ldr und str, um Werte in und aus den FPU-Registern zu laden bzw. zu speichern.
- Arithmetische Operationen: Verwendung von speziellen Instruktionen wie fadd (Addition), fsub (Subtraktion), fmul (Multiplikation) und fdiv (Division) für Gleitkommaarithmetik.
- Beachtung von Doppelpräzisionsregistern: Verwenden Sie d-Register für doppelpräzise Gleitkommazahlen.
- Parameterübergabe: Gleitkommaargumente werden in den d0 bis d7 Registern übergeben, ähnlich wie Ganzzahlen in x0 bis x7.
Beispiel: Gleitkommamultiplikation in einer Funktion
Funktionsdefinition in C:
// float_functions.c
double multiply(double a, double b) {
return a * b;
}
Aufruf der Funktion aus Assembler:
.extern multiply
.global _start
_start:
// Parameter für die Funktion laden
ldr x0, =var1
ldr d0, [x0]
ldr x1, =var2
ldr d1, [x1]
// Aufruf der C-Funktion
bl multiply
// Das Ergebnis ist in d0
// Beispiel: Gleitkommaergebnis weiter verarbeiten
// (hier nicht weiter verwendet)
// Exit system call
mov x8, #93
mov x0, #0
svc 0
Funktionsdefinition im Assembler:
.global multiply
multiply:
fmul d0, d0, d1 // Führe die Multiplikation durch: d0 = d0 * d1
ret // Rückkehr zur aufrufenden Funktion
Parameterübergabe und Rückgabewert
Wie bereits erwähnt, werden Gleitkommaargumente in den Registern d0 bis d7 übergeben und Rückgabewerte in d0. Hier ein Beispiel, das zeigt, wie Sie eine Gleitkommafuntionsdefinition in Assembler schreiben und von C aus aufrufen.
C-Beispiel:
// main.c
#include <stdio.h>
extern double asm_multiply(double a, double b);
int main() {
double result = asm_multiply(3.14, 1.618);
printf("Ergebnis: %f\n", result);
return 0;
}
Assemblerfunktion:
.global asm_multiply
asm_multiply:
fmul d0, d0, d1 // Führe die Multiplikation durch: d0 = d0 * d1
ret // Rückkehr zur aufrufenden Funktion
Kompilierung und Linken:
gcc -c main.c
as -o float_functions.o float_functions.s
gcc -o myprogram main.o float_functions.o
Beispiele für die Verwendung
Addition (fadd)
.section .data
var1: .double 3.14
var2: .double 1.618
.section .text
.global _start
_start:
ldr x0, =var1
ldr d0, [x0] // Lade var1 in d0
ldr x1, =var2
ldr d1, [x1] // Lade var2 in d1
fadd d2, d0, d1 // d2 = d0 + d1 (3.14 + 1.618)
// Exit system call
mov x8, #93
mov x0, #0
svc 0
Subtraktion (fsub)
.section .data
var1: .double 3.14
var2: .double 1.618
.section .text
.global _start
_start:
ldr x0, =var1
ldr d0, [x0] // Lade var1 in d0
ldr x1, =var2
ldr d1, [x1] // Lade var2 in d1
fsub d2, d0, d1 // d2 = d0 - d1 (3.14 - 1.618)
// Exit system call
mov x8, #93
mov x0, #0
svc 0
Multiplikation (fmul)
.section .data
var1: .double 3.14
var2: .double 1.618
.section .text
.global _start
_start:
ldr x0, =var1
ldr d0, [x0] // Lade var1 in d0
ldr x1, =var2
ldr d1, [x1] // Lade var2 in d1
fmul d2, d0, d1 // d2 = d0 * d1 (3.14 * 1.618)
// Exit system call
mov x8, #93
mov x0, #0
svc 0
Division (fdiv)
.section .data
var1: .double 3.14
var2: .double 1.618
.section .text
.global _start
_start:
ldr x0, =var1
ldr d0, [x0] // Lade var1 in d0
ldr x1, =var2
ldr d1, [x1] // Lade var2 in d1
fdiv d2, d0, d1 // d2 = d0 / d1 (3.14 / 1.618)
// Exit system call
mov x8, #93
mov x0, #0
svc 0
Konvertierung von Gleitkommazahlen
Ganzzahl zu Gleitkommazahl (scvtf / ucvtf)
.section .data
int_val: .word 10
.section .text
.global _start
_start:
ldr w0, =int_val
ldr w1, [w0] // Lade int_val in w0
scvtf d0, w1 // Wandle signed integer w1 in double d0 um
// Exit system call
mov x8, #93
mov x0, #0
svc 0
Gleitkommazahl zu Ganzzahl (fcvtzs / fcvtzu)
.section .data
float_val: .double 3.14
.section .text
.global _start
_start:
ldr x0, =float_val
ldr d0, [x0] // Lade float_val in d0
fcvtzs w1, d0 // Wandle double d0 in signed integer w1 um
// Exit system call
mov x8, #93
mov x0, #0
svc 0
Vergleich von Gleitkommazahlen und bedingte Sprungbefehle
Vergleich von Gleitkommazahlen (fcmpe / fcsel)
.section .data
var1: .double 3.14
var2: .double 1.618
.section .text
.global _start
_start:
ldr x0, =var1
ldr d0, [x0] // Lade var1 in d0
ldr x1, =var2
ldr d1, [x1] // Lade var2 in d1
fcmpe d0, d1 // Vergleiche d0 und d1
b.gt greater // Springe zu 'greater', wenn d0 > d1
// Kleiner oder gleich Fall
le_or_eq:
// Hierher wird gesprungen, wenn d0 <= d1
// (Z.B. Füge Code für diesen Fall hinzu)
b exit
greater:
// Hierher wird gesprungen, wenn d0 > d1
// (Z.B. Füge Code für diesen Fall hinzu)
exit:
// Exit system call
mov x8, #93
mov x0, #0
svc 0
Wichtiger Hinweis: fcmpe: Vergleich von Gleitkommazahlen nach IEEE 754. fcmp: Vergleich von Gleitkommazahlen ohne Exception (unsicherer Vergleich).
Beide Vergleichsoperationen verwenden die gleichen Vergleichsflags (N, Z, C, V), wie bei Ganzzahlenvergleichen.