对汇编FLD指令m64fp感到困惑

时间:2015-05-24 07:15:04

标签: assembly floating-point x86 fpu

我很困惑。我对FLD m64fp指令有一些疑问,但我不知道从哪里开始。因为这是一个家庭作业,我不是专门要求答案,而是解决问题的方法。任何建议或想法将不胜感激。

内存中的八个连续字节包含十六进制值01,00,00,00,00,00,00,00.执行FLD m64fp指令。它的参数是这八个连续字节中第一个的地址。作为FLD指令的结果,ST(0)中的值现在为:

1)  2^(-1075)
2)  2^(-1074)   
3)  2^(-1023)
4)  2^(-1022) 

另外,如果我有以下汇编代码

   │0x8048384 <main>                lea    0x4(%esp),%ecx                                                                                                                                               │
   │0x8048388 <main+4>              and    $0xfffffff0,%esp                                                                                                                                             │
   │0x804838b <main+7>              pushl  -0x4(%ecx)                                                                                                                                                   │
   │0x804838e <main+10>             push   %ebp                                                                                                                                                         │
   │0x804838f <main+11>             mov    %esp,%ebp                                                                                                                                                    │
   │0x8048391 <main+13>             push   %ecx                                                                                                                                                         │
   │0x8048392 <main+14>             fldpi                                                                                                                                                               │
   │0x8048394 <main+16>             fsqrt                                                                                                                                                               │
   │0x8048396 <main+18>             fld1                                                                                                                                                                │
   │0x8048398 <main+20>             fsubrp %st,%st(1)                                                                                                                                                   │
   │0x804839a <main+22>             mov    $0x0,%eax                                                                                                                                                    │
   │0x804839f <main+27>             pop    %ecx                                                                                                                                                         │
   │0x80483a0 <main+28>             pop    %ebp                                                                                                                                                         │
   │0x80483a1 <main+29>             lea    -0x4(%ecx),%esp                                                                                                                                              │
   │0x80483a4 <main+32>             ret   

如何在主要返回之前找出ST(0)中的值? 谢谢。

1 个答案:

答案 0 :(得分:3)

让我们从第一个问题开始。

没有明确说明,但我认为我们可以假设我们在这里处理小端(你今天使用的每台PC都会使用它)。因此,如果在该内存位置上执行FLD m64p,则浮点堆栈将以相反的顺序包含这些字节 - 即00 00 00 00 00 00 00 01。让我们看一下双精度格式的样子: enter image description here

现在,这实际上是一种特殊情况 - 由于指数为零且尾数不是,我们代表一个subnormal数字 - 一个无法使用标准化尾数表示的数字,即整数部分为1(1.xxx) - 它需要前导零(记住,因为指数有偏差(1023),零实际上意味着1 - exponent (0) - 1023这里,所以-1022

正如Wikipedia告诉我们的那样,我们可以使用以下公式计算次正规数的值: enter image description here

然而,尾数中的最低有效位(并且只有那一位)被设置,这给尾数​​值2^(-52)(因为我们在双精度格式中有52位用于尾数)。

因此,如果我们使用该公式,我们得到的是:
(-1)^0 x 2^(1-1023) x 2^(-52) = 1 x 2^(-1022) x 2^(-52) = 2^(-1022 - 52) = 2^(-1074),即答案2.

这是最小可能的正次正规数 - 如果未设置最后一位,则这些位代表带符号零

要测试(或者更容易找到结果,如果你感到懒惰:),你可以使用OllyDbg for Windows,它允许你动态修改汇编代码。让我们输入问题中给出的指令:

enter image description here

并让字节设置为所需的值:

enter image description here

的确,当我们执行时,我们得到了这个:

enter image description here

这几乎等于2 ^ (-1074)



现在,关于第二个问题。 让我们分析您列出的说明。

  1. 我们从fldpi开始,相当于ST(0) = PI
  2. 我们执行fsqrt,现在我们已ST(0) = sqrt(PI)
  3. fld1将一个加载到ST(0),因此堆栈如下所示:ST(0) = 1ST(1) = sqrt(PI)
  4. fsubrp执行反转减法并弹出寄存器堆栈。由于这是AT&amp; T程序集,而buggy one就是这个,所以源是第一个,因此我们从ST(0)中减去ST(1),将结果存储在ST(1)中,然后弹出寄存器堆栈使ST(1)变为ST(0)。实际上,现在我们有ST(0) = sqrt(PI) - 1,接近0.772。当ST(0)返回时,此值保留在main,因为之后没有任何内容会修改浮点堆栈。