对汇编FLD指令m64fp感到困惑

Confused about assembly FLD instruction m64fp

我很困惑。我对 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    [=11=]xfffffff0,%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    [=11=]x0,%eax                                                                                                                                                    │
   │0x804839f <main+27>             pop    %ecx                                                                                                                                                         │
   │0x80483a0 <main+28>             pop    %ebp                                                                                                                                                         │
   │0x80483a1 <main+29>             lea    -0x4(%ecx),%esp                                                                                                                                              │
   │0x80483a4 <main+32>             ret   

如何找出 ST(0) 中 main returns 之前的值? 谢谢。

让我们从第一个问题开始

它没有明确说明,但我认为我们可以假设我们在这里处理 little-endian(您今天要使用的每台 PC 都会使用它)。因此,如果您在该内存位置执行 FLD m64p,浮点堆栈将以相反的顺序包含这些字节 - 即 00 00 00 00 00 00 00 01。让我们看看双精度格式是什么样的:

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

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

但是,设置了尾数中的最低有效位(并且只有那个),这使尾数的值为 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 作为 Windows,它允许你修改汇编代码苍蝇。让我们输入问题中给出的指令:

让我们将字节设置为所需的值:

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

(几乎)等于 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 执行 reversed 减法并弹出寄存器堆栈。由于这是 AT&T 程序集,并且那里有一个 buggy one,源在前,所以我们从 ST(1) 中减去 ST(0),将结果存储在 ST(1) 中,然后弹出寄存器堆叠使 ST(1) 变为 ST(0)。实际上,现在我们有 ST(0) = sqrt(PI) - 1,接近 0.772。当 main returns 时,此值保留在 ST(0) 中,因为稍后没有任何内容修改浮点堆栈。