《Reverse Engineering for Beginners》 - 第1章 代码模式 - 笔记(1.18)

1.18. 浮点数单元

CPU中的FPU

1.18.1. IEEE 754

sign+significand+exponent

1.18.2. x86

一开始FPU和CPU是分开的,FWAIT用来转换CPU状态,等待FPU完成工作。FPU有一个栈,用来保存8个80比特的寄存器ST(0)……ST(7)。

1.18.3. ARM, MIPS, x86/x64 SIMD

ARM和MIPS不是栈,而是一些寄存器,在x86/x64的SIMD拓展也是。

1.18.4. C/C++

2种浮点类型,float(32bits)和double(64bits)。

1.18.5. 简单例子

return and printf a/3.15+b*4.1

x86

MSVC
fld QWORD PTR _a$[ebp]
fdiv QWORD PTR _real@40091eb851eb851f 即a/3.14
ST(0)=a, 用a/3.14放入ST(0)
ST(0)=b,先把ST(0)->ST(1)因为是栈
ST(0)=b*4.1 -> ST(0)
把ST(0)、ST(1)加起来->ST(0)
MSVC+OllyDbg

注意FPU的这个栈是循环的。

GCC

不一样的是,第一步ST(0)=3.14

fdivv [ebp+arg_0], 其中arg_0存放a

乘法也是,乘数与被乘数顺序与x86不同。

ARM:优化的Xcode(LLVM)(ARM模式)

VFP标准,没有栈,只有寄存器,D开头双精度,S开头单精度。

Thumb-2的代码是一样的。

ARM:优化的Keil(Thumb模式)

调用了一些库函数,模拟FPU,但其实是软件实现的。经济。

ARM64:优化的GCC
ldr d2, .LC25 ;3.14
fdiv d0, d0, d2 ;计算除法
ldr d2, .LC26 ;4.1
fwadd d0, d1, d2, d0 ;计算乘法和加法
ret
ARM64:非优化的GCC

没有必要地把值倒来倒去。

MIPS

最多可以支持4个coprocessor。也没有栈,用寄存器。

LWC1加载32位字到第一个coprocessor的寄存器。

DIV.D MUL.D ADD.D

1.18.6. 通过参数传递浮点数

一个简单的例子:

printf(“32.01 ^ 1.54 = %lf\n”, pow(32.01, 1.54));

x86

先给第一个变量分配空间,然后使用fld和fstp指令。这两个指令把变量在数据段和FPU栈之间进行移动。所以这两条语句实现了将32.01从数据段移到栈中。同样地,1.54也被移到栈中,然后调用了pow函数,函数返回值存放在ST(0)中。然后用fstp从ST(0)移动到本地栈,调用printf函数。

ARM和未优化的Xcode(LLVM)(Thumb-2模式)

64位的浮点数是用寄存器传递的,而不是栈。未优化的代码有点冗余。pow函数接收R0+R1为第一个参数,R2+R3为第二个参数。结果保存在R0+R1。pow函数的结果随后会被移动到D16中,然后再存到R1+R2里,printf就从这两个寄存器接受参数。

ARM和未优化的Keil(ARM模式)

还是用R0+R1存第一个参数,R2+R3存第二个参数。然后直接把pow函数结果放到了R3+R2,然后调用printf,不过这里没有使用D开头的寄存器,只使用了R开头的寄存器。

AMR64和优化的GCC

常数加载到D0和D1,这是pow的参数。结果放在D0中。然后会把D0直接传递给printf。实际上printf一般从X寄存器取整数类型值,从D寄存器取浮点数类型值。

MIPS

LUI指令将浮点数的32位放到 V0

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值