FPU环境
FPU 寄存器栈
8个80位的数据寄存器(R0~R7)
16位的状态寄存器
状态位
描述
0
不合法的操作
1
不规范化的操作
2
除数为0的异常
3
上溢出异常
4
下溢出异常
5
精度异常
6
栈错误
7
错误总体状态
8
状态码C0
9
状态码C1
10
状态码C2
11~13
栈顶指针
14
状态码C3
15
FPU忙标志
* 示例
# getstatus.s - Get the FPU Status register contents
.section .bss
.lcomm status, 2
.section .text
.globl _start
_start:
nop
fstsw %ax
fstsw status
movl $1, %eax
movl $0, %ebx
int $0x80
* 16位的控制寄存器
* 状态位
控制位
描述
0
不合法的操作异常掩码
1
不合规范的操作异常掩码
2
除于0异常掩码
3
上溢出异常掩码
4
下溢出异常掩码
5
精度异常掩码
6-7
保留
8-9
精度控制
10-11
凑整控制
12
无穷控制
13-15
保留
* 精度控制
值
描述
00
单精度(24位有效位)
01
没有使用
10
双精度(53位有效位)
11
双扩展精度(64位有效位)default
* 凑整控制
值
描述
00
向最近值取整 default
01
向下取整
10
向上取整
11
向0取整
* 示例
# setprec.s - An example of setting the precision bits in the Control Register
.section .data
newvalue:
.byte 0x7f, 0x00
.section .bss
.lcomm control, 2
.section .text
.globl _start
_start:
nop
fstcw control
fldcw newvalue
fstcw control
movl $1, %eax
movl $0, %ebx
int $0x80
* 16位的标签寄存器
* 格式
14-15
12-13
10-11
8-9
6-7
4-5
2-3
0-1
R7
R6
R5
R4
R3
R2
R1
R0
* 值
* 00 : 合法的双扩展精度值
* 01 : 零值
* 10 : 一个特殊的单精度值
* 11 : 空值
* 使用FPU栈
* 示例
# stacktest.s - An example of working with the FPU stack
.section .data
value1:
.int 40
value2:
.float 92.4405
value3:
.double 221.440321
.section .bss
.lcomm int1, 4
.lcomm control, 2
.lcomm status, 2
.lcomm result, 4
.section .text
.globl _start
_start:
nop
finit
fstcw control
fstsw status
filds value1
fists int1
flds value2
fld1 value3
fst %st(4)
fxch %st(1)
fstps result
movl $1, %eax
movl $0, %ebx
int $0x80
* 说明
FINIT : 初始化状态和控制寄存器
FILDS : 将一个双字整数放入FPU寄存器
FISTS : 检索栈顶元素,并放入目的地址
FLDS: 将一个单精度的浮点数放入寄存器
FLDL: 将一个双精度的浮点数放入寄存器
FST: 将ST0寄存器的值存入另外一个寄存器,不取出栈顶元素
FSTP: 取出栈顶值并放入另外一个寄存器
FXCH: 用于和ST0寄存器交换元素
基本的浮点数运算
指令
描述
FADD
浮点数加法
FDIV
浮点数除法
FDIVR
逆向浮点数加法
FMUL
浮点数乘法
FSUB
浮点数减法
FSUBR
逆向浮点数减法
* 指令描述
FADD source : source + ST0 -> ST0
FADD %st(x), %st(0) : STX + ST0 -> ST0
FADD %st(0) , %st(x) : ST0 + STX -> STX
FADDP %st(0), %st(x) : ST0 + STX -> STX, pop ST0
FADDP : ST0 + ST1 -> ST1, pop ST0
FIADD source : source( 16 or 32 bits int) + ST0 -> ST0
# ((43.65 / 22) + (76.34 * 3.1)) / ((12.43 * 6) - (140.2 / 94.21))
# fpmath.s - An example of basic FPU math
.section .data
value1:
.float 43.65
value2:
.int 22
value3:
.float 76.34
value4:
.float 3.1
value5:
.float 12.43
value6:
.float 6
value7:
.float 140.2
value8:
.float 94.21
output:
.asciz "The result is %f\n"
.section .text
.globl _start
_start:
nop
finit
flds value1
fidiv value2
flds value3
flds value4
fmul %st(1), %st(0)
fadd %st(2), %st(0)
flds value5
fimul value6
flds value7
flds value8
fdivrp
fsubr %st(1), %st(0)
fdivr %st(2), %st(0)
subl $8, %esp
fstpl (%esp)
pushl $output
call printf
add $12, %esp
pushl $0
call exit
高级的浮点数运算
指令
描述
F2XM1
计算ST0的2次方,然后减一
FABS
计算ST0的绝对值
FCHS
对ST0的值取反
FCOS
计算ST0的余弦值
FPATAN
计算ST0的局部饭正切
FPREM
计算ST0/ST1的余数
FPREM1
计算ST0/ST1的IEEE格式余数
FPTAN
计算ST0的正切
FRNDINT
四舍五入ST0到整数
FSCAL
计算ST0的ST1次方
FSIN
计算ST0的正弦
FSINCOS
计算ST0的正弦和余弦
FSQRT
计算ST0的平方根
FYL2X
计算ST1*logST0(base 2)
FYL2XP1
计算ST1*log(ST0+1)(base 2)
# fpmath2.s - An example of the FABS, FCHS, and PSQRT instructions
.section .data
value1:
.float 395.21
value2:
.float -9145.290
value3:
.float 64.0
.section .text
.globl _start
_start:
nop
finit
flds value1
fchs
flds vlaue2
fabs
flds value3
fsqrt
mov $1, %eax
mov $0, %ebx
int $0x80
(gdb) info all
# roundtest.s - An example of the FRNDINT instruction
.section .data
value1:
.float 3.65
rdown:
.byte 0x7f, 0x07
rup:
.byte 0x7f, 0x0b
.section .bss
.lcomm result1, 4
.lcomm result2, 4
.lcomm result3, 4
.section .text
.globl _start
_start:
nop
finit
flds value1
frndint
fists result1
fldcw rdown
flds value1
frndint
fists result2
fldcw rup
flds value1
frndint
fists result3
movl $1, %eax
movl $0, %ebx
int $0x80
# premtest.s - An example of using the FPREM1 instruction
.section .data
value1:
.float 20.65
value2:
.float 3.97
.section .bss
.lcomm result, 4
.section .text
.globl _start
_start:
nop
finit
flds value2
flds value1
loop:
fprem1
fstsw %ax
testb $4, %ah
jnz loop
fsts result
movl $1, %eax
movl $0, %ebx
int $0x80
# trigtest.s - An example of using the FSIN and FCOS instructions
.section .data
degree1:
.float 90.0
val180:
.int 180
.section .bss
.lcomm radian1, 4
.lcomm result1, 4
.lcomm result2, 4
.section .text
.globl _start
_start:
nop
finit
flds degree1
fidivs val180
fldpi
fmul %st(1), %st(0)
fsts randian1
fsin
fsts result1
flds randian1
flds randian1
fcos
fsts result2
movl $1, %eax
movl $0, %ebx
int $0x80
浮点数的条件分支
指令
描述
FCOM
比较ST0与ST1
FCOM ST(x)
比较ST0与STX
FCOM source
比较ST0与source
FCOMP
比较ST0与ST1,popST0
FCOMP ST(X)
比较后出栈
FCOMP source
比较后出栈
FCOMPP
比较后出栈2次
FTST
比较ST0与0
条件
C3
C2
C0
ST0 > source
0
0
0
ST0 < source
0
0
1
ST0 == source
1
0
0
# fcomtest.s - An example of the FCOM instruction
.section .data
value1:
.float 10.923
value2:
.float 4.5532
.section .text
.globl _start
_start:
nop
flds value1
fcoms value2
fstsw
sahf
ja greater
jb lessthan
movl $1, %eax
movl $0, %eax
int $0x80
greater:
movl $1, %eax
movl $2, %eax
int $0x80
lessthan:
movl $1, %eax
movl $1, %eax
int $0x80
指令
描述
FCOMI
比较ST0与ST1
FCOMIP
比较ST0与ST(X), 然后出栈
FUCOMI
比较前检查无序值
FUCOMIP
比较前检查无序值并出栈
条件
ZF
PF
CF
ST0 > ST(x)
0
0
0
ST0 < ST(x)
0
0
1
ST0 = ST(x)
1
0
0
# fcomitest.s - An example of the FCOMI instruction
.section .data
value1:
.float 10.923
value2:
.float 4.5532
.section .text
.globl _start
_start:
nop
flds value2
flds value1
fcomi %st(1), %st(0)
ja greater
jb lessthan
movl $1, %eax
movl $0, %eax
int $0x80
greater:
movl $1, %eax
movl $2, %eax
int $0x80
lessthan:
movl $1, %eax
movl $1, %eax
int $0x80
指令
描述
FCMOVB
如果ST0 < ST(x) 移动
FCMOVE
如果ST0 = ST(x) 移动
FCMOVBE
如果ST0 <= ST(x) 移动
FCMOVU
如果ST0无序 移动
FCMOVNB
如果!ST0 < ST(x) 移动
FCMOVNE
如果 !ST0 = ST(x) 移动
FCMOVNBE
如果! ST0 <= ST(x) 移动
FCMOVNU
如果!ST0无序 移动
# fcmovtest.s - An example of the FCMOVxx instruction
.section .data
value1:
.float 20.5
value2:
.float 10.90
.section .text
.globl _start
_start:
nop
finit
flds value1
flds value2
fcomi %st(1), %st(0)
fcmovb %st(1), %st(0)
movl $1, %eax
movl $0, %ebx
int $0x80
保存和设置FPU状态
保存和重载FPU环境
命令
FSEENV
保存内容
控制寄存器
状态寄存器
标签寄存器
FPU指令指针偏移
FPU数据指针
FPU上次操作码执行结果
示例
# fpuenv.s - An example of the FSTENV and FLDENV instructions
.section .data
value1:
.float 12.34
value2:
.float 56.789
rup:
.byte 0x7f, 0x0b
.section .bss
.lcomm buffer, 28
.section .text
.globl _start
_start:
nop
finit
flds value1
flds value2
fldcw rup
fstenv buffer
finit
flds value2
flds value1
fldenv buffer
movl $1, %eax
movl $0, %ebx
int $0x80
#fpusave.s - An example of the FSAVE and FRSTOR instructions
.section .data
value1:
.float 12.34
value2:
.float 56.789
rup:
.byte 0x7f, 0x0b
.section .bss
.lcomm buffer, 108
.section .text
.globl _start
_start:
nop
finit
flds value1
flds value2
fldcw rup
fsave buffer
flds value2
flds value1
frstor buffer
movl $1, %eax
movl $0, %ebx
int $0x80
指令
描述
FNCLEX
清除浮点数异常标识
FNSAVE
保存FPU状态
FNSTCW
保存FPU控制寄存器
FNSTENV
保存FPU环境
FNSTSW
保存FPU状态寄存器
优化浮点数运算
确保浮点数没有溢出
设置单精度浮点数的精度控制标识
对简单的三角函数运算使用查找表
将链式运算拆解
尽量长的保存方程式的值
尽量将INT转换成浮点数,再运算
使用FCOMI 代替FCOM