Fundamentos da Programação com a FPU x87
Aprenda a usar a Unidade de Ponto Flutuante x87 (FPU) para realizar operações aritméticas de ponto flutuante com alta precisão em Assembly.
Fundamentos da Programação com a FPU x87 é uma aula grátis de Assembly Language & x86 Low-Level Systems Programming no CoddyKit. Esta é a aula 1 de 4. Você pode ler a aula completa abaixo gratuitamente — depois pratica ao vivo no navegador com um editor de código integrado e um tutor de IA 24/7. Faz parte do caminho de aprendizado de Assembly Language & x86 Low-Level Systems Programming, e seu progresso é sincronizado entre a web e o app CoddyKit. O curso de Assembly Language & x86 Low-Level Systems Programming inclui 4 aulas no total.
Partes desta aula ainda não foram traduzidas e aparecem em inglês.
Meet the x87 FPU
The x87 Floating-Point Unit (FPU) is a specialized part of the CPU designed to handle mathematical operations on real numbers, also known as floating-point numbers.
Unlike integer arithmetic, floating-point math requires different internal representations and calculations, which the FPU excels at with high precision.
The FPU Register Stack
The x87 FPU uses a unique register stack, not general-purpose registers. This stack consists of eight 80-bit registers, denoted as ST(0) through ST(7).
ST(0)is always the top of the stack.- Operations push new values onto the stack or pop values from it, shifting existing values.
- It behaves like a Last-In, First-Out (LIFO) stack.
Loading Data with FLD
To work with floating-point numbers, you first need to load them onto the FPU stack. The FLD instruction pushes a floating-point value from memory onto the top of the FPU stack, making it ST(0).
In assembly, we often define floating-point constants in the data section. Common types are single-precision (32-bit, DD) and double-precision (64-bit, DQ).
Try loading a value onto the stack:
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
syscallStoring FPU Results
After calculations, you'll want to store the result from the FPU stack back into memory. The FST and FSTP instructions are used for this.
FST: Copies the value fromST(0)to a memory location or another FPU register, leavingST(0)unchanged.FSTP: Copies the value fromST(0)to memory/register, then pops it from the stack, decreasing the stack pointer. The previousST(1)becomesST(0).
Let's store a value:
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
syscallFPU Arithmetic Operations
The FPU provides instructions for common arithmetic operations. These typically operate on ST(0) and another operand (either another stack register or a memory operand).
FADD: Add (e.g.,FADD ST(1), ST(0)addsST(0)toST(1)).FMUL: MultiplyFSUB: SubtractFDIV: Divide
Using FADDP ST(1), ST(0) adds ST(0) to ST(1), stores in ST(1), and pops ST(0). This leaves the sum on top of the stack.
Here's an addition example:
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 Built-in Constants
The FPU can load commonly used constants directly onto its stack, saving you from defining them in memory. This improves efficiency and precision.
FLD1: Pushes 1.0 onto the stack.FLDZ: Pushes 0.0 onto the stack.FLDPI: Pushes the value of Pi (π) onto the stack.
Let's load 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
syscallConverting Integers & Floats
Sometimes you need to convert between integer and floating-point types. The FPU provides instructions for this:
FILD(Float Integer Load): Loads a signed integer from memory, converts it to a floating-point format, and pushes it onto the FPU stack.FISTP(Float Integer Store and Pop): StoresST(0)as an integer to memory and then pops it from the stack. The value is truncated towards zero during conversion.
Let's convert an integer to a float, add, then convert back:
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
syscallComparing Floating-Point Values
Comparing floating-point numbers requires special FPU instructions. You can't directly use integer comparison instructions like CMP.
FCOM: ComparesST(0)with an operand (another FPU register or memory) and sets FPU status flags.FCOMP: Same asFCOM, but popsST(0)after comparison.
To use these flags for conditional jumps (like JE, JB), you must transfer them from the FPU status word to the CPU's EFLAGS register:
FSTSW AX: Stores the FPU Status Word into theAXregister.SAHF: Transfers theAHregister (which now contains the relevant FPU flags) into the CPU'sEFLAGSregister, specifically theZF,PF, andCFflags.
Putting it Together: (A + B) * C
Let's combine what we've learned to perform a simple calculation: (A + B) * C. We'll load three values, add two, multiply by the third, and store the final integer result.
This example demonstrates stack manipulation and arithmetic operations.
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 Stack Challenge
Consider the following x87 FPU assembly code snippet. What will be the value of ST(0) after its execution?
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)x87 FPU Summary
You've taken your first steps into x87 FPU programming! We covered:
- The FPU's 8-register stack (
ST(0)toST(7)). - Loading values with
FLDand storing withFST/FSTP. - Basic arithmetic:
FADD,FSUB,FMUL,FDIV. - Using built-in constants like
FLD1,FLDZ,FLDPI. - Converting between integers and floats with
FILDandFISTP. - How to prepare FPU comparison results for conditional jumps.
The x87 FPU is powerful for precise calculations, though modern systems often use SIMD extensions like SSE/AVX for speed, which you'll explore next!
Perguntas Frequentes
A aula “Fundamentos da Programação com a FPU x87” é grátis?
Sim — o texto completo de “Fundamentos da Programação com a FPU x87” é grátis para ler aqui na web. Para praticá-la interativamente (um editor de código integrado e um tutor de IA 24/7) e desbloquear o restante do curso de Assembly Language & x86 Low-Level Systems Programming, atualize para CoddyKit PRO. O curso de Assembly Language & x86 Low-Level Systems Programming inclui 4 aulas no total.
O que vou aprender em “Fundamentos da Programação com a FPU x87”?
Aprenda a usar a Unidade de Ponto Flutuante x87 (FPU) para realizar operações aritméticas de ponto flutuante com alta precisão em Assembly. Você pratica Assembly Language & x86 Low-Level Systems Programming com código prático que executa diretamente no navegador, e um tutor de IA 24/7 responde suas dúvidas enquanto trabalha na aula.
Preciso ter experiência prévia para começar Assembly Language & x86 Low-Level Systems Programming?
Nenhuma experiência prévia é necessária. Assembly Language & x86 Low-Level Systems Programming no CoddyKit é estruturado para alunos iniciantes até avançados, então você pode começar aqui ou desde o início e aprender no seu ritmo. Esta é a aula 1 de 4.
Quanto tempo leva a aula “Fundamentos da Programação com a FPU x87”?
A maioria das aulas CoddyKit leva cerca de 5–10 minutos. Cada uma é compacta e interativa, então você faz progresso constante e retoma exatamente de onde parou entre web e app.
Posso escrever e executar código nesta aula de Assembly Language & x86 Low-Level Systems Programming?
Sim. Cada aula de Assembly Language & x86 Low-Level Systems Programming inclui um editor de código integrado, então você escreve e executa código real direto no navegador e recebe feedback de IA instantaneamente — nenhuma configuração local necessária.
Todas as aulas deste curso
- Fundamentos da Programação com a FPU x87
- Introdução aos Conjuntos de Instruções SSE/AVX
- Vetorização de Código com SIMD
- Precisão de ponto flutuante, arredondamento e exceções