对汇编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)
。
现在,关于第二个问题。
让我们分析一下您列出的指令。
- 我们从
fldpi
开始,相当于ST(0) = PI
。
- 我们执行
fsqrt
,所以现在我们有ST(0) = sqrt(PI)
。
fld1
将一个加载到 ST(0)
,因此堆栈如下所示:ST(0) = 1
、ST(1) = sqrt(PI)
.
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)
中,因为稍后没有任何内容修改浮点堆栈。
我很困惑。我对 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)
。
现在,关于第二个问题。
让我们分析一下您列出的指令。
- 我们从
fldpi
开始,相当于ST(0) = PI
。 - 我们执行
fsqrt
,所以现在我们有ST(0) = sqrt(PI)
。 fld1
将一个加载到ST(0)
,因此堆栈如下所示:ST(0) = 1
、ST(1) = sqrt(PI)
.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)
中,因为稍后没有任何内容修改浮点堆栈。