首页
社区
课程
招聘
[分享]常用的浮点指令
发表于: 2005-3-18 14:24 6736

[分享]常用的浮点指令

2005-3-18 14:24
6736
浮点指令

  对下面的指令先做一些说明:
st(i):代表浮点寄存器,所说的出栈、入栈操作都是对st(i)的影响
src,dst,dest,op等都是指指令的操作数,src表示源操作数,dst/dest表示目的操作数
mem8,mem16,mem32,mem64,mem80等表示是内存操作数,后面的数值表示该操作数的内存位数(8位为一字节)
x <- y 表示将y的值放入x,例st(0) <- st(0) - st(1)表示将st(0)-st(1)的值放入浮点寄存器st(0)

1. 数据传递和对常量的操作指令

指令格式
指令含义
执行的操作

FLD src
装入实数到st(0)
st(0) <- src (mem32/mem64/mem80)

FILD src
装入整数到st(0)
st(0) <- src (mem16/mem32/mem64)

FBLD src
装入BCD数到st(0)
st(0) <- src (mem80)

FLDZ
将0.0装入st(0)
st(0) <- 0.0

FLD1
将1.0装入st(0)
st(0) <- 1.0

FLDPI
将pi装入st(0)
st(0) <- ?(ie, pi)

FLDL2T
将log2(10)装入st(0)
st(0) <- log2(10)

FLDL2E
将log2(e)装入st(0)
st(0) <- log2(e)

FLDLG2
将log10(2)装入st(0)
st(0) <- log10(2)

FLDLN2
将loge(2)装入st(0)
st(0) <- loge(2)

FST dest
保存实数st(0)到dest
dest <- st(0) (mem32/mem64)

FSTP dest

dest <- st(0) (mem32/mem64/mem80);然后再执行一次出栈操作

FIST dest
将st(0)以整数保存到dest
dest <- st(0) (mem32/mem64)

FISTP dest

dest <- st(0) (mem16/mem32/mem64);然后再执行一次出栈操作

FBST dest
将st(0)以BCD保存到dest
dest <- st(0) (mem80)

FBSTP dest

dest<- st(0) (mem80);然后再执行一次出栈操作

2.比较指令

指令格式
指令含义
执行的操作

FCOM
实数比较
将标志位设置为 st(0) - st(1) 的结果标志位

FCOM op
实数比较
将标志位设置为 st(0) - op (mem32/mem64)的结果标志位

FICOM op
和整数比较
将Flags值设置为st(0)-op 的结果op (mem16/mem32)

FICOMP op
和整数比较
将st(0)和op比较 op(mem16/mem32)后;再执行一次出栈操作

FTST
零检测
将st(0)和0.0比较

FUCOM st(i)

比较st(0) 和st(i) [486]

FUCOMP st(i)

比较st(0) 和st(i),并且执行一次出栈操作

FUCOMPP st(i)

比较st(0) 和st(i),并且执行两次出栈操作

FXAM

Examine: Eyeball st(0) (set condition codes)

3.运算指令

指令格式
指令含义
执行的操作

加法

FADD
加实数
st(0) <-st(0) + st(1)

FADD src

st(0) <-st(0) + src (mem32/mem64)

FADD st(i),st

st(i) <- st(i) + st(0)

FADDP st(i),st

st(i) <- st(i) + st(0);然后执行一次出栈操作

FIADD src
加上一个整数
st(0) <-st(0) + src (mem16/mem32)

减法

FSUB
减去一个实数
st(0) <- st(0) - st(1)

FSUB src

st(0) <-st(0) - src (reg/mem)

FSUB st(i),st

st(i) <-st(i) - st(0)

FSUBP st(i),st

st(i) <-st(i) - st(0),然后执行一次出栈操作

FSUBR st(i),st
用一个实数来减
st(0) <- st(i) - st(0)

FSUBRP st(i),st

st(0) <- st(i) - st(0),然后执行一次出栈操作

FISUB src
减去一个整数
st(0) <- st(0) - src (mem16/mem32)

FISUBR src
用一个整数来减
st(0) <- src - st(0) (mem16/mem32)

乘法

FMUL
乘上一个实数
st(0) <- st(0) * st(1)

FMUL st(i)

st(0) <- st(0) * st(i)

FMUL st(i),st

st(i) <- st(0) * st(i)

FMULP st(i),st

st(i) <- st(0) * st(i),然后执行一次出栈操作

FIMUL src
乘上一个整数
st(0) <- st(0) * src (mem16/mem32)

除法

FDIV
除以一个实数
st(0) <-st(0) /st(1)

FDIV st(i)

st(0) <- st(0) /t(i)

FDIV st(i),st

st(i) <-st(0) /st(i)

FDIVP st(i),st

st(i) <-st(0) /st(i),然后执行一次出栈操作

FIDIV src
除以一个整数
st(0) <- st(0) /src (mem16/mem32)

FDIVR st(i),st
用实数除
st(0) <- st(i) /st(0)

FDIVRP st(i),st

FDIVRP st(i),st

FIDIVR src
用整数除
st(0) <- src /st(0) (mem16/mem32)

FSQRT
平方根
st(0) <- sqrt st(0)

FSCALE
2的st(0)次方
st(0) <- 2 ^ st(0)

FXTRACT
Extract exponent:
st(0) <-exponent of st(0); and gets pushed

st(0) <-significand of st(0)

FPREM
取余数
st(0) <-st(0) MOD st(1)

FPREM1
取余数(IEEE),同FPREM,但是使用IEEE标准[486]

FRNDINT
取整(四舍五入)
st(0) <- INT( st(0) ); depends on RC flag

FABS
求绝对值
st(0) <- ABS( st(0) ); removes sign

FCHS
改变符号位(求负数)
st(0) <-st(0)

F2XM1
计算(2 ^ x)-1
st(0) <- (2 ^ st(0)) - 1

FYL2X
计算Y * log2(X)
st(0)为Y;st(1)为X;将st(0)和st(1)变为st(0) * log2( st(1) )的值

FCOS
余弦函数Cos
st(0) <- COS( st(0) )

FPTAN
正切函数tan
st(0) <- TAN( st(0) )

FPATAN
反正切函数arctan
st(0) <- ATAN( st(0) )

FSIN
正弦函数sin
st(0) <- SIN( st(0) )

FSINCOS
sincos函数
st(0) <-SIN( st(0) ),并且压入st(1)

st(0) <- COS( st(0) )

FYL2XP1
计算Y * log2(X+1)
st(0)为Y; st(1)为X; 将st(0)和st(1)变为st(0) * log2( st(1)+1 )的值

处理器控制指令

FINIT
初始化FPU

FSTSW AX
保存状态字的值到AX
AX<- MSW

FSTSW dest
保存状态字的值到dest
dest<-MSW (mem16)

FLDCW src
从src装入FPU的控制字
FPU CW <-src (mem16)

FSTCW dest
将FPU的控制字保存到dest
dest<- FPU CW

FCLEX
清除异常

FSTENV dest
保存环境到内存地址dest处 保存状态字、控制字、标志字和异常指针的值

FLDENV src
从内存地址src处装入保存的环境

FSAVE dest
保存FPU的状态到dest处 94字节

FRSTOR src
从src处装入由FSAVE保存的FPU状态

FINCSTP
增加FPU的栈指针值
st(6) <-st(5); st(5) <-st(4),...,st(0) <-?

FDECSTP
减少FPU的栈指针值
st(0) <-st(1); st(1) <-st(2),...,st(7) <-?

FFREE st(i)
标志寄存器st(i)未被使用

FNOP
空操作,等同CPU的nop
st(0) <-st(0)

WAIT/FWAIT
同步FPU与CPU:停止CPU的运行,直到FPU完成当前操作码

FXCH
交换指令,交换st(0)和st(1)的值
st(0) <-st(1)

st(1) <- st(0)

--------------------------------------------

[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 339
活跃值: (1510)
能力值: ( LV13,RANK:970 )
在线值:
发帖
回帖
粉丝
2
我来顶一下!

  29A 8#浮点指令教程(FPU instructions tutorial)

来源:29A第8期
翻译:nbw   nbwo.blogbus.com
注:
  翻译的不好,有些地方没弄明白,没敢翻译,有些地方不翻译了(cos,sin)。翻译这东西主要为了自己熟悉一下,因为看一遍实在体会不深刻。
  既然出于这目的,我也不能保证翻译的正确性,希望大家原谅!

你或许想为什么要写或者读一篇关于FPU指令的教程,如果你认为这对写病毒没什么帮助,也无助于改善生活,那么你就想错了。
这些指令会有很大帮助。

顾名生义,浮点指令不仅支持整数,也支持十进制小数。相信我这些指令可以帮你躲避杀毒软件的检测(效果也不错:))。怎么实现呢?

只需在加密/解密部分或者变形引擎中利用它们处理一下。因为半数的杀毒软件在检测这些指令时会挂起或者忽略这些文件,这样你就可以
隐藏自己。

现在我们开始正题:

首先应该检测一下你的系统是否支持FPU指令集。也就是检查一下是否配备了协处理器。这个可以通过一条简单的指令来监测:SMSW EAX
检查一下低位,为1,则有协处理器支持,否则我们可以跑去看电影了。

看一下协处理器,如果处理器位386,486,586....,那么协处理器为387,487,587....以及相应的FPIs。

现在看一下IEEE标准754标准文档,这些是用FPU处理浮点数据的Intel标准文档。

指令格式如下:
  S-Sign, E-Exponent, F-Fraction 或简单表达为: S,E,F.
S的长度为1bit(定点为0,否则为1)。F的长度为:总长度-E长度-1。

一般浮点数表达形式为:S,2^E*F

这里,FPU为我们提供了专门的“堆栈”来进行计算或者保存数据等操作,包括:
  ST(0), ST(1), ST(2),....ST(9)
ST(0)也可以称为ST。相关操作执行时,这些堆栈用来存放浮点数据。

现在看一下操作数的载入过程。当第一次载入时候,数据被存放在ST,以后每次操作,堆栈上升,开始被载入的操作数也随之上移,
直到ST(9)。比如:
        load a : ST(0) = a; ST(1) = 0; ST(2) = 0.....
        load b : ST(0) = b; ST(1) = a; ST(2) = 0.....
        load c : ST(0) = c; ST(1) = b; ST(2) = a.....         
希望这里已经把事情讲明白了。
最常用到的寄存器是ST(0)和ST(1)。
下面是从文档中查到的FPU指令表。
        
            谀哪哪哪哪哪哪哪哪哪哪哪哪哪哪?
            ?     数据转移和常量     ?
            滥哪哪哪哪哪哪哪哪哪哪哪哪哪哪?         

FLD src   装载实数: st(0) = src (mem32/mem64/mem80)
FILD src 装载整数: st(0) = src (mem16/mem32/mem64)
FBLD src 装载BCD: st(0) = src (mem80)

FLDZ   清零: st(0) = 0.0
FLD1   置1: st(0) = 1.0
FLDPI   载入圆周率: st(0) = ?(ie, pi)
FLDL2T   载入 log2(10): st(0) = log2(10)
FLDL2E   载入 log2(e): st(0) = log2(e)
FLDLG2   载入 log10(2): st(0) = log10(2)
FLDLN2   载入 loge(2): st(0) = loge(2)

FST dest 保存实数: dest = st(0) (mem32/mem64)
FSTP dest dest = st(0) (mem32/mem64/mem80) and pop stack
FIST dest 保存整数: dest = st(0) (mem32/mem64)
FISTP dest dest = st(0) (mem16/mem32/mem64) and pop stack
FBST dest 保存 BCD: dest = st(0) (mem80)
FBSTP dest dest = st(0) (mem80) and pop stack

                  谀哪哪哪哪?
                  ?   比较 ?
                  滥哪哪哪哪?

FCOM   比较实数: Set flags as for st(0) - st(1)
FCOM op   设定st(0)的标记 - op (mem32/mem64)
FCOMP op 比较 st(0) 和 op (reg/mem); 然后出栈
FCOMPP   比较 st(0) 和 st(1) 并出栈操作2次
FICOM op 比较整数: 设置st(0)标记 - op (mem16/mem32)
FICOMP op 比较 st(0) 和 op (mem16/mem32) 并出栈

FTST   判零操作: 比较 st(0) 是否为 0.0

FUCOM st(i) 无序比较: st(0) to st(i) [486]
FUCOMP st(i) 比较 st(0) 和 st(i) 并出栈
FUCOMPP st(i) 比较 st(0) 和 st(i) 并出栈2次

FXAM   检查: st(0) (设置条件代码)(译:我也不懂)

              谀哪哪哪哪哪目
              ?   运算   ?
              滥哪哪哪哪哪馁

FADD   加实数: st(0) = st(0) + st(1)
FADD src st(0) = st(0) + src (mem32/mem64)
FADD st(i),st st(i) = st(i) + st(0)
FADDP st(i),st st(i) = st(i) + st(0) and pop stack
FIADD src 加整数: st(0) = st(0) + src (mem16/mem32)

FSUB   减实数: st(0) = st(0) - st(1)
FSUB src st(0) = st(0) - src (reg/mem)
FSUB st(i),st st(i) = st(i) - st(0)
FSUBP st(i),st st(i) = st(i) - st(0) and pop stack
FSUBR st(i),st 减去保留数: st(0) = st(i) - st(0)
FSUBRP st(i),st st(0) = st(i) - st(0); pop stack
FISUB src 减去整数: st(0) = st(0) - src (mem16/mem32)
FISUBR src 减去保留的整数: st(0) = src - st(0) (mem16/mem32)

FMUL   乘以实数: st(0) = st(0) * st(1)
FMUL st(i) st(0) = st(0) * st(i)
FMUL st(i),st st(i) = st(0) * st(i)
FMULP st(i),st st(i) = st(0) * st(i) and pop stack
FIMUL src     乘以整数: st(0) = st(0) * src (mem16/mem32)

FDIV   除以实数: st(0) = st(0) ?st(1)
FDIV st(i) st(0) = st(0) ?t(i)
FDIV st(i),st st(i) = st(0) ?st(i)
FDIVP st(i),st st(i) = st(0) ?st(i) and pop stack
FIDIV src 除以整数: st(0) = st(0) ?src (mem16/mem32)
FDIVR st(i),st 除以保留的实数: st(0) = st(i) ?st(0)
FDIVRP st(i),st   st(0) = st(i) ?st(0) and pop stack(译:除法操作后有出栈操作)
FIDIVR src 除以保留的整数: st(0) = src ?st(0) (mem16/mem32)

FSQRT   开方: st(0) = sqrt st(0)

FSCALE   求2的幂: st(0) = 2 ^ st(0)

FXTRACT   Extract exponent: st(0) = exponent of st(0) and gets pushed
                      as st(0) = significand of st(0)

FPREM   Partial remainder: st(0) = st(0) MOD st(1)
FPREM1   Partial Remainder (IEEE): same as FPREM, but in IEEE standard [486]

FRNDINT   Round to nearest int: st(0) = INT( st(0) ), depends on RC flag

FABS   Get absolute value: st(0) = ABS( st(0) ), removes sign (changes to postive)
FCHS   Change sign: st(0) = -st(0)

              谀哪哪哪哪哪哪哪目
              ?Transcendental ?
              滥哪哪哪哪哪哪哪馁

FCOS   Cosine: st(0) = COS( st(0) )
FPTAN   Partial tangent: st(0) = TAN( st(0) )
FPATAN.   Partial Arctangent: st(0) = ATAN( st(0) )
FSIN   Sine: st(0) = SIN( st(0) )
FSINCOS   Sine and Cosine: st(0) = SIN( st(0) ) and is pushed to st(1)
                      st(0) = COS( st(0) )

F2XM1   Calculate (2 ^ x)-1: st(0) = [2 ^ st(0)] - 1

FYL2X   Calculate Y * log2(X): st(0) is Y, st(1) is X; this replaces st(0) and
st(1) with: st(0) * log2( st(1) )

FYL2XP1   Calculate Y * log2(X+1): st(0) is Y; st(1) is X; this replaces st(0)
                      and st(1) with: st(0) * log2( st(1)+1 )

              谀哪哪哪哪哪哪哪哪哪?
              ?Processor Control ?
              滥哪哪哪哪哪哪哪哪哪?

FINIT   初始化FPU
FSTSW AX STore Status Word in EAX., ie. EAX = MSW
FSTSW dest dest = MSW (mem16)

FLDCW src LoaD Control Word: FPU CW = src (mem16)
FSTCW dest STore Control Word: dest = FPU CW

FCLEX   Clear exceptions

FSTENV dest STore ENVironment: stores status, control and tag words
and exception pointers into memory at dest

FLDENV src LoaD ENVironment: loads environment from memory at src

FSAVE dest Store FPU state: store FPU state into 94-bytes at dest

FRSTOR src Load FPU state: restore FPU state as saved by FSAVE

FINCSTP Increment FPU stack ptr: st(6)<-st(5); st(5)<-st(4),...,st(0)

FDECSTP Decrement FPU stack ptr: st(0)<-st(1); st(1)<-st(2),...,st(7)
    The above 2 instuctions put the corresponding values too in the
    inc/dec stacks.

FFREE st(i) Mark reg st(i) as unused

FNOP No operation: st(0) = st(0), equivalent to nop.

WAIT/FWAIT Synchronize FPU & CPU: Halt CPU until FPU finishes current opcode.

FXCH - eXCHange instruction     st(0) <- st(1)
                      st(1) <- st(0) similar to xchg.
                     
假设我们需要做以下操作:                       

          tan(cos(sin(a*b+c*d)))/4

需要做的很简单,具体如下:

首先,需要知道,在数据载入以前,首先采用FILD初始化,因为按照IEEE354文档,FLD需要一个整数。
我想说的是,假设你需要将变量VAR初始化为12345678h,那么,当使用FLD VAR获取类似于1.2345e-67
(很恐怖?)。但是如果你使用FILD指令,VAR被载入12345678h,并且这也是我们需要的。

下面看一下具体代码:

          finit             ;该句非常必要
          fild dword ptr [a]     ;ST(0) = a, dwords形式
          fild dword ptr     ;ST(0) = b, ST(1) = a
          fadd             ;ST(0) = a+b
          fistp dword ptr [Var]   ;Var=ST(0), 存放在临时变量中
          fild dword ptr [c]     ;ST(0) = c
          fild dword ptr [d]     ;ST() = d, ST(1) = c
          fadd             ;ST(0) = c+d
          fild dword ptr [Var]   ;ST(0) = Var, ST(1) = c+d
          fmul             ;ST(0) = Var*(c+d)
          fsin             ;sin of ST(0)
          fcos             ;cos of ST(0)
          ftan             ;tan of ST(0)
          mov Var2, 4h         ;Var2 = 4
          fild dword ptr [Var2]   ;ST(0) = Var2 = 4, ST(1) = tan(cos(sin(a*b+c*d)))/4
很简单,也很长?
另外需要注意的地方是,需要指定.387(或者.487,.587)。
比如:
          .386
          .387
          .data
                [...]
          .code
                [...]
          End
这些指定声明了对32位FPU寄存器的使用。

如果有问题,请联系:aks8586@yahoo.com

-Surya/powerdryv
-23rd June, 2004         

译者备注:
最下面举例,计算:

tan(cos(sin(a*b+c*d)))/4

作者的代码:

  finit             ;thats very very necesarry
          fild dword ptr [a]     ;ST(0) = a, we work in dwords
          fild dword ptr     ;ST(0) = b, ST(1) = a
          fadd             ;ST(0) = a+b

                          ;这句应该是fmul

          fistp dword ptr [Var]   ;Var=ST(0), store in a temp. variable
          fild dword ptr [c]     ;ST(0) = c

          fild dword ptr [d]     ;ST() = d, ST(1) = c

                          ;应为“ST(0) = d,”

          fadd             ;ST(0) = c+d

                          ;这句应该是fmul

          fild dword ptr [Var]   ;ST(0) = Var, ST(1) = c+d
          fmul             ;ST(0) = Var*(c+d)
          fsin             ;sin of ST(0)
          fcos             ;cos of ST(0)
          ftan             ;tan of ST(0)
          mov Var2, 4h         ;Var2 = 4
          fild dword ptr [Var2]   ;ST(0) = Var2 = 4, ST(1) = tan(cos(sin(a*b+c*d)))/4

我不懂fpu,或许说的不对。。

29A出此文,让人有些郁闷,真有凑文之嫌
2005-3-18 14:32
0
雪    币: 107
活跃值: (54)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
upup
2005-3-18 17:14
0
雪    币: 519
活跃值: (1223)
能力值: ( LV12,RANK:650 )
在线值:
发帖
回帖
粉丝
4
对浮点指令机器码的反汇编,正在学习中....
2005-3-18 19:12
0
雪    币: 4908
活跃值: (2343)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
5
语句的最后还是没有除以4

我觉得最后应该这样:

fild 4   ;把04h放入st(0)
fild dword ptr [Var2]   ;ST(1) = Var2 = 4, ST(0) = tan(cos(sin(a*b+c*d)))
fdiv      ;除以4的结果在st(0)中
2005-3-18 20:25
0
游客
登录 | 注册 方可回帖
返回
//