Grunderna i x87 FPU-programmering
Lär dig använda x87 Floating-Point Unit (FPU) för flyttalsaritmetik med hög precision i Assembly.
Grunderna i x87 FPU-programmering är en gratis lektion i Assembler och lågnivåprogrammering för x86-system på CoddyKit. Detta är lektion 1 av 4. Ni kan läsa hela lektionen gratis nedan och sedan öva praktiskt i webbläsaren med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt. Den ingår i lärvägen för Assembler och lågnivåprogrammering för x86-system, och Era framsteg synkroniseras mellan webben och CoddyKit-appen. Kursen i Assembler och lågnivåprogrammering för x86-system innehåller totalt 4 lektioner.
Lär känna x87 FPU
x87 Floating-Point Unit (FPU) är en specialiserad del av processorn som är utformad för att hantera matematiska operationer på reella tal, även kallade flyttal.
Till skillnad från heltalsaritmetik kräver flyttalsberäkningar andra interna representationer och beräkningar, något som FPU:n hanterar med hög precision.
FPU:ns registerstack
x87 FPU använder en unik registerstack, inte allmänna register. Stacken består av åtta 80-bitarsregister, betecknade ST(0) till och med ST(7).
ST(0)är alltid överst i stacken.- Operationer lägger nya värden på stacken eller tar bort värden från den, vilket flyttar befintliga värden.
- Den fungerar som en LIFO-stack (Last-In, First-Out).
Läsa in data med FLD
För att arbeta med flyttal måste du först läsa in dem på FPU-stacken. Instruktionen FLD lägger ett flyttalsvärde från minnet överst på FPU-stacken, vilket gör värdet till ST(0).
I assembler definierar vi ofta flyttalskonstanter i datasegmentet. Vanliga typer är enkel precision (32 bitar, DD) och dubbel precision (64 bitar, DQ).
Prova att läsa in ett värde på stacken:
section .data
float_val dq 3.1415926535
section .text
global _start
_start:
finit ; Initialize FPU
fld qword [float_val] ; Load float_val onto FPU stack (ST(0))
; At this point, ST(0) contains 3.1415926535
; We just exit as printing floats is complex in basic assembly.
mov rax, 60 ; syscall number for exit
xor rdi, rdi ; exit code 0
syscallLagra FPU-resultat
Efter beräkningarna vill du lagra resultatet från FPU-stacken tillbaka i minnet. Instruktionerna FST och FSTP används för detta.
FST: Kopierar värdet frånST(0)till en minnesadress eller ett annat FPU-register utan att ändraST(0).FSTP: Kopierar värdet frånST(0)till minnet eller ett register och tar sedan bort det från stacken, vilket minskar stackpekaren. Det tidigareST(1)blirST(0).
Nu lagrar vi ett värde:
section .data
float_val dq 123.45
result_val dq 0.0 ; Will store result here
section .text
global _start
_start:
finit ; Initialize FPU
fld qword [float_val] ; ST(0) = 123.45
fstp qword [result_val] ; Store ST(0) to result_val, then pop.
; FPU stack is now empty.
; result_val now holds 123.45 in memory.
mov rax, 60 ; syscall number for exit
xor rdi, rdi ; exit code 0
syscallAritmetiska FPU-operationer
FPU:n tillhandahåller instruktioner för vanliga aritmetiska operationer. Dessa arbetar vanligtvis med ST(0) och en annan operand (antingen ett annat stackregister eller en minnesoperand).
FADD: Addera (till exempel adderarFADD ST(1), ST(0)ST(0)tillST(1)).FMUL: MultipliceraFSUB: SubtraheraFDIV: Dividera
Med FADDP ST(1), ST(0) adderas ST(0) till ST(1), resultatet lagras i ST(1) och ST(0) tas bort från stacken. Då ligger summan överst i stacken.
Här är ett exempel på addition:
section .data
val1 dq 10.5
val2 dq 2.0
sum_result dq 0.0
section .text
global _start
_start:
finit ; Initialize FPU
fld qword [val1] ; ST(0) = 10.5
fld qword [val2] ; ST(0) = 2.0, ST(1) = 10.5
faddp st(1), st(0) ; ST(1) = ST(1) + ST(0) (10.5 + 2.0 = 12.5).
; Pop ST(0). Now ST(0) = 12.5.
fstp qword [sum_result] ; Store 12.5 to sum_result and pop.
mov rax, 60 ; syscall number for exit
xor rdi, rdi ; exit code 0
syscallFPU:ns inbyggda konstanter
FPU:n kan läsa in vanligt förekommande konstanter direkt på stacken, så att du slipper definiera dem i minnet. Detta förbättrar effektiviteten och precisionen.
FLD1: Lägger 1.0 på stacken.FLDZ: Lägger 0.0 på stacken.FLDPI: Lägger värdet av Pi (π) på stacken.
Nu läser vi in Pi:
section .data
pi_val dq 0.0 ; To store PI
section .text
global _start
_start:
finit ; Initialize FPU
fldpi ; ST(0) = PI (approx 3.14159...)
fstp qword [pi_val] ; Store PI to pi_val and pop.
mov rax, 60 ; syscall number for exit
xor rdi, rdi ; exit code 0
syscallKonvertera heltal och flyttal
Ibland behöver du konvertera mellan heltalstyper och flyttalstyper. FPU:n tillhandahåller instruktioner för detta:
FILD(Float Integer Load): Läser in ett teckenförsett heltal från minnet, konverterar det till flyttalsformat och lägger det på FPU-stacken.FISTP(Float Integer Store and Pop): LagrarST(0)som ett heltal i minnet och tar sedan bort värdet från stacken. Vid konverteringen trunkeras värdet mot noll.
Nu konverterar vi ett heltal till ett flyttal, adderar och konverterar sedan tillbaka:
section .data
int_val dd 5
float_add dq 2.5
int_result dd 0
section .text
global _start
_start:
finit ; Initialize FPU
fild dword [int_val] ; ST(0) = 5.0 (from 5)
fld qword [float_add] ; ST(0) = 2.5, ST(1) = 5.0
faddp st(1), st(0) ; ST(1) = 5.0 + 2.5 = 7.5. Pop ST(0).
; Now ST(0) = 7.5.
fistp dword [int_result] ; Store 7.5 as integer (7) to int_result and pop.
mov rax, 60 ; syscall number for exit
xor rdi, rdi ; exit code 0
syscallJämföra flyttalsvärden
För att jämföra flyttal krävs särskilda FPU-instruktioner. Du kan inte använda heltalsinstruktioner för jämförelse, som CMP, direkt.
FCOM: JämförST(0)med en operand (ett annat FPU-register eller minnet) och ställer in FPU:ns statusflaggor.FCOMP: Fungerar somFCOM, men tar bortST(0)efter jämförelsen.
För att använda dessa flaggor vid villkorliga hopp (som JE och JB) måste du överföra dem från FPU:ns statusord till processorns EFLAGS-register:
FSTSW AX: Lagrar FPU:ns statusord i registretAX.SAHF: Överför registretAH(som nu innehåller de relevanta FPU-flaggorna) till processornsEFLAGS-register, närmare bestämt flaggornaZF,PFochCF.
Sätta ihop det: (A + B) * C
Nu kombinerar vi det vi har lärt oss för att utföra en enkel beräkning: (A + B) * C. Vi läser in tre värden, adderar två av dem, multiplicerar med det tredje och lagrar det slutliga heltalsresultatet.
Exemplet visar hur stacken hanteras och hur aritmetiska operationer utförs.
section .data
val_A dq 3.0
val_B dq 1.5
val_C dq 2.0
final_int_result dd 0
section .text
global _start
_start:
finit ; Initialize FPU
fld qword [val_A] ; ST(0) = 3.0
fld qword [val_B] ; ST(0) = 1.5, ST(1) = 3.0
faddp st(1), st(0) ; Add ST(0) (1.5) to ST(1) (3.0), store in ST(1).
; Pop ST(0). Now ST(0) = 4.5 (sum of A+B)
fld qword [val_C] ; ST(0) = 2.0, ST(1) = 4.5 (A+B)
fmulp st(1), st(0) ; Multiply ST(0) (2.0) by ST(1) (4.5), store in ST(1).
; Pop ST(0). Now ST(0) = 9.0 ((A+B)*C)
fistp dword [final_int_result] ; Store 9.0 as integer (9) to final_int_result and pop.
mov rax, 60 ; syscall number for exit
xor rdi, rdi ; exit code 0
syscallFPU-stackutmaning
Betrakta följande kodavsnitt med x87 FPU-assembler. Vilket värde har ST(0) efter körningen?
section .data
val_X dq 10.0
val_Y dq 3.0
section .text
finit
fld qword [val_X] ; ST(0) = 10.0
fld qword [val_Y] ; ST(0) = 3.0, ST(1) = 10.0
faddp st(1), st(0) ; ST(0) = 13.0
fld1 ; ST(0) = 1.0, ST(1) = 13.0
fsub ; ST(0) = ST(0) - ST(1) (1.0 - 13.0 = -12.0)Sammanfattning av x87 FPU
Du har tagit dina första steg inom x87 FPU-programmering! Vi gick igenom:
- FPU:ns stack med åtta register (
ST(0)tillST(7)). - Att läsa in värden med
FLDoch lagra dem medFST/FSTP. - Grundläggande aritmetik:
FADD,FSUB,FMULochFDIV. - Att använda inbyggda konstanter som
FLD1,FLDZochFLDPI. - Att konvertera mellan heltal och flyttal med
FILDochFISTP. - Hur du förbereder resultat från FPU-jämförelser för villkorliga hopp.
x87 FPU är kraftfull för precisa beräkningar, även om moderna system ofta använder SIMD-utökningar som SSE/AVX för högre hastighet, vilket du utforskar härnäst!
Lär dig Assembly med en AI-lärare – gratis
Skriv och kör riktig kod i webbläsaren, få omedelbar hjälp av en AI-lärare dygnet runt och fortsätt där du slutade – på webben eller i appen.
- Kurser
- 12
- Lektioner
- 48
Vanliga frågor
Är lektionen ”Grunderna i x87 FPU-programmering” gratis?
Ja – hela texten till ”Grunderna i x87 FPU-programmering” kan läsas gratis här på webben. Om Ni vill öva interaktivt med en inbyggd kodredigerare och en AI-handledare som är tillgänglig dygnet runt och låsa upp resten av kursen i Assembler och lågnivåprogrammering för x86-system, kan Ni uppgradera till CoddyKit PRO. Kursen i Assembler och lågnivåprogrammering för x86-system innehåller totalt 4 lektioner.
Vad lär jag mig i ”Grunderna i x87 FPU-programmering”?
Lär dig använda x87 Floating-Point Unit (FPU) för flyttalsaritmetik med hög precision i Assembly. Ni övar på Assembler och lågnivåprogrammering för x86-system med praktisk kod som körs direkt i webbläsaren, medan en AI-handledare som är tillgänglig dygnet runt svarar på Era frågor under lektionen.
Behöver jag någon erfarenhet för att börja lära mig Assembler och lågnivåprogrammering för x86-system?
Du behöver inga förkunskaper. Utbildningen i Assembler och lågnivåprogrammering för x86-system på CoddyKit är upplagd för allt från nybörjare till avancerade elever, så att du kan börja här eller från början och gå fram i din egen takt. Detta är lektion 1 av 4.
Hur lång tid tar lektionen ”Grunderna i x87 FPU-programmering”?
De flesta CoddyKit-lektioner tar cirka 5–10 minuter. Varje lektion är kort och interaktiv, så att du gör stadiga framsteg och kan fortsätta precis där du slutade – på webben eller i appen.
Kan jag skriva och köra kod i den här Assembler och lågnivåprogrammering för x86-system-lektionen?
Ja. Varje Assembler och lågnivåprogrammering för x86-system-lektion innehåller en inbyggd kodredigerare, så att du kan skriva och köra riktig kod direkt i webbläsaren och få omedelbar AI-feedback – utan lokal installation.
Alla lektioner i den här kursen
- Grunderna i x87 FPU-programmering
- Introduktion till SSE/AVX-instruktionsuppsättningar
- Vektorisera kod med SIMD
- Flyttalsprecision, avrundning och undantag