【问题标题】:C printf function does not work properly in NASM assemblyC printf 函数在 NASM 程序集中无法正常工作
【发布时间】:2015-03-07 21:53:15
【问题描述】:

我正在尝试使用用 C 编写的 printTime() 函数来测试我的 32 位 NASM 程序的运行时间。

void printTime(float time){
    printf("The cpu time is %e \n" , time);
}

这是 NASM 代码的一部分:

push edi           <---------------- Here edi holds int 6580001
call printTime
pop edi

这里是GCC生成的汇编代码,我使用GDB跟踪每一步:

push ebp
mov esp, ebp
sub 0x8, esp
flds 0x8(esp)     <-------  x/d ($esp+0x8) gives me 6580001, the correct number
sub 0x4,esp
lea -0x8(esp),esp
fstpl (esp)
push 0x80486f6
call 0x8048370 <printf@plt>  <--- it prints 9.220545e-39 here, which is wrong
add 0x10, esp
leave
ret

谁能告诉我为什么 printf 函数打印错误而不是 6.58001e+5 ?我很感激。

【问题讨论】:

  • 好吧,你传递了一个 int 并且 printTime 需要一个浮点数。它们有不同的二进制表示。请参阅此处h-schmidt.net/FloatConverter/IEEE754.html 并输入 0x646721(您的十六进制数字)作为“十六进制表示”
  • @Roddy 嘿,非常感谢。

标签: c assembly nasm


【解决方案1】:

您正在将一个整数加载到浮点寄存器中,并期望它被视为浮点中的相同值。这不是 IEEE754 浮点的工作方式,数字使用不同的编码方案。

整数65800010x00646701)形成的位模式如下分析图所示。浮点数由符号、有偏指数和小数部分组成。

seee eeee efff ffff ffff ffff ffff ffff
0000-0000 0110-0100 0110-0111 0000-0001

首先,让我们处理标志。是0,这意味着这个数字是正数。这很容易:-)

指数位全为零,并且在 IEEE754 编码中,您通常会减去 127 的偏差并提高 2 的幂以获得乘数。

但是,对全零指数进行特殊处理(这些是非规范化数字)。首先,在小数位上加一的常规做法(见下文)并未完成。其次,将乘数调整为2<sup>-126</sup>而不是2<sup>-127</sup>

这就是乘数1.1754943508222875079687365372222 x 10<sup>-38</sup>

对于小数位,您通常会将其位置值加一(减少二的倒数),但由于它是非规范化的,因此您跳过加一:

110-0100 0110-0111 0000-0001
||   |    ||   |||         |
||   |    ||   |||         +- 1/8M  = 0.00000011920928955078125
||   |    ||   ||| (64K-4M)
||   |    ||   ||+----------- 1/32K = 0.000030517578125
||   |    ||   |+------------ 1/16K = 0.00006103515625
||   |    ||   +------------- 1/8K  = 0.0001220703125
||   |    ||       (2K,4K)
||   |    |+----------------- 1/1K  = 0.0009765625
||   |    +------------------ 1/512 = 0.001953125
||   |             (64-256)
||   +----------------------- 1/32  = 0.03125
||                 (8,16)
|+--------------------------- 1/4   = 0.25
+---------------------------- 1/2   = 0.5
                                      0.78439342975616455078125

要获得实际数字,您可以将该结果与之前计算的乘数相乘,得到9.2205004550049022573489420224302 x 10<sup>-39</sup>,这就是您所看到的结果。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多