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\n1) 2^(-1075)\n2) 2^(-1074) \n3) 2^(-1023)\n4) 2^(-1022) \nRun 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 \nRun Code Online (Sandbox Code Playgroud)\n\n我如何找出 main 返回之前 ST(0) 中的值?\n谢谢。
\n我们先从第一个问题开始。
虽然没有明确说明,但我认为我们可以假设我们在这里处理的是小端字节序(您今天使用的每台 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)。
现在,关于第二个问题。让我们分析一下您列出的说明。
fldpi,这相当于ST(0) = PI。fsqrt,所以现在我们有了ST(0) = sqrt(PI)。fld1将一个加载到 中ST(0),因此堆栈如下所示:ST(0) = 1, ST(1) = sqrt(PI)。fsubrp执行反向减法并弹出寄存器堆栈。由于这是 AT&T 汇编,并且是一个有缺陷的汇编,因此源是第一个,因此我们ST(0)从 中减去ST(1),将结果存储在 中ST(1),然后弹出寄存器堆栈,以便ST(1)变为ST(0)。实际上,现在我们已经ST(0) = sqrt(PI) - 1接近0.772。ST(0)该值在返回时保留main,因为稍后不会修改浮点堆栈。| 归档时间: |
|
| 查看次数: |
1820 次 |
| 最近记录: |