x87 FPU 编程基础
学习如何使用 x87 浮点运算单元(FPU)在汇编语言中执行高精度浮点运算。
x87 FPU 编程基础 是 CoddyKit 上的免费 Assembly Language & x86 Low-Level Systems Programming 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Assembly Language & x86 Low-Level Systems Programming 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Assembly Language & x86 Low-Level Systems Programming 课程共包含 4 节课。
本课时的部分内容尚未翻译,以英文显示。
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!
常见问题解答
「x87 FPU 编程基础」课时是免费的吗?
是的 — 「x87 FPU 编程基础」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Assembly Language & x86 Low-Level Systems Programming 课程的其余内容,请升级到 CoddyKit PRO。 Assembly Language & x86 Low-Level Systems Programming 课程共包含 4 节课。
「x87 FPU 编程基础」这节课中我会学到什么?
学习如何使用 x87 浮点运算单元(FPU)在汇编语言中执行高精度浮点运算。 你通过在浏览器中直接运行的动手代码来练习 Assembly Language & x86 Low-Level Systems Programming,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 Assembly Language & x86 Low-Level Systems Programming 需要有经验吗?
无需任何先前经验。CoddyKit 上的 Assembly Language & x86 Low-Level Systems Programming 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「x87 FPU 编程基础」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 Assembly Language & x86 Low-Level Systems Programming 课中编写并运行代码吗?
能。每节 Assembly Language & x86 Low-Level Systems Programming 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- x87 FPU 编程基础
- SSE/AVX 指令集简介
- 使用 SIMD 将代码向量化
- 浮点精度、舍入与异常