对汇编 FLD 指令 m64fp 感到困惑

shj*_*lee 3 floating-point x86 assembly fpu

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

\n\n

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

\n\n
1)  2^(-1075)\n2)  2^(-1074)   \n3)  2^(-1023)\n4)  2^(-1022) \n
Run Code Online (Sandbox Code Playgroud)\n\n

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

\n\n
   \xe2\x94\x820x8048384 <main>                lea    0x4(%esp),%ecx                                                                                                                                               \xe2\x94\x82\n   \xe2\x94\x820x8048388 <main+4>              and    $0xfffffff0,%esp                                                                                                                                             \xe2\x94\x82\n   \xe2\x94\x820x804838b <main+7>              pushl  -0x4(%ecx)                                                                                                                                                   \xe2\x94\x82\n   \xe2\x94\x820x804838e <main+10>             push   %ebp                                                                                                                                                         \xe2\x94\x82\n   \xe2\x94\x820x804838f <main+11>             mov    %esp,%ebp                                                                                                                                                    \xe2\x94\x82\n   \xe2\x94\x820x8048391 <main+13>             push   %ecx                                                                                                                                                         \xe2\x94\x82\n   \xe2\x94\x820x8048392 <main+14>             fldpi                                                                                                                                                               \xe2\x94\x82\n   \xe2\x94\x820x8048394 <main+16>             fsqrt                                                                                                                                                               \xe2\x94\x82\n   \xe2\x94\x820x8048396 <main+18>             fld1                                                                                                                                                                \xe2\x94\x82\n   \xe2\x94\x820x8048398 <main+20>             fsubrp %st,%st(1)                                                                                                                                                   \xe2\x94\x82\n   \xe2\x94\x820x804839a <main+22>             mov    $0x0,%eax                                                                                                                                                    \xe2\x94\x82\n   \xe2\x94\x820x804839f <main+27>             pop    %ecx                                                                                                                                                         \xe2\x94\x82\n   \xe2\x94\x820x80483a0 <main+28>             pop    %ebp                                                                                                                                                         \xe2\x94\x82\n   \xe2\x94\x820x80483a1 <main+29>             lea    -0x4(%ecx),%esp                                                                                                                                              \xe2\x94\x82\n   \xe2\x94\x820x80483a4 <main+32>             ret   \n
Run Code Online (Sandbox Code Playgroud)\n\n

我如何找出 main 返回之前 ST(0) 中的值?\n谢谢。

\n

use*_*520 5

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

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

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

正如维基百科告诉我们的,我们可以使用以下公式计算次正规数的值: 在此输入图像描述

然而,尾数中的最低有效位(并且只有那个位)被设置,这给尾数​​一个值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。

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

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

在此输入图像描述

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

在此输入图像描述

事实上,当我们执行它时,我们得到了这个:

在此输入图像描述

这(几乎)等于2 ^ (-1074)



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

  1. 我们从 开始fldpi,这相当于ST(0) = PI
  2. 我们执行fsqrt,所以现在我们有了ST(0) = sqrt(PI)
  3. fld1将一个加载到 中ST(0),因此堆栈如下所示:ST(0) = 1, ST(1) = sqrt(PI)
  4. fsubrp执行反向减法并弹出寄存器堆栈。由于这是 AT&T 汇编,并且是一个有缺陷的汇编,因此源是第一个,因此我们ST(0)从 中减去ST(1),将结果存储在 中ST(1),然后弹出寄存器堆栈,以便ST(1)变为ST(0)。实际上,现在我们已经ST(0) = sqrt(PI) - 1接近0.772ST(0)该值在返回时保留main,因为稍后不会修改浮点堆栈。