高级的数学方法

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
  • FSIN 和 FCOS 指令
# 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指令
指令 描述
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 指令
指令 描述
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
  • FCMOV 指令
指令 描述
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
  • 保存和重载FPU状态
    • 指令
      FSAVE
    • 示例
#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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章