C printf功能在NASM组装中无法正常工作

时间:2015-03-07 21:53:16

标签: c assembly nasm

我正在尝试使用用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?我很感激。

1 个答案:

答案 0 :(得分:1)

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

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

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

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

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

但是,特殊处理全零指数(这些是非规范化数字)。首先,没有完成向分数位添加一个的常规做法(见下文)。其次,将乘数调整为2-126而不是2-127

这使得乘数1.1754943508222875079687365372222 x 10-38

对于小数位,通常会添加一个带有它们的位置值(减少2的倒数)但是,由于它是非规范化的,你跳过添加一个:

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-39,这是您所看到的结果。