我很困惑。我对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)中的值? 谢谢。
答案 0 :(得分:3)
让我们从第一个问题开始。
没有明确说明,但我认为我们可以假设我们在这里处理小端(你今天使用的每台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 for Windows,它允许你动态修改汇编代码。让我们输入问题中给出的指令:
并让字节设置为所需的值:
的确,当我们执行时,我们得到了这个:
这几乎等于2 ^ (-1074)
。
现在,关于第二个问题。
让我们分析您列出的说明。
fldpi
开始,相当于ST(0) = PI
。fsqrt
,现在我们已ST(0) = sqrt(PI)
。fld1
将一个加载到ST(0)
,因此堆栈如下所示:ST(0) = 1
,ST(1) = sqrt(PI)
。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
,因为之后没有任何内容会修改浮点堆栈。