为什么这个简单的程序会输出这么多字符?

Nat*_*man 0 x86 assembly printf x87

这是我的装配程序:

; This code has been generated by the 7Basic
; compiler <http://launchpad.net/7basic>

extern printf

; Initialized data

      SECTION .data
f_0 dd 5.5
printf_f: db "%f",10,0

      SECTION .text

; Code

global main
  main:
push ebp
mov ebp,esp

push dword [f_0]
push printf_f
call printf
add esp,8

mov esp,ebp
pop ebp
mov eax,0
ret
Run Code Online (Sandbox Code Playgroud)

该程序应该做的是打印5.5,但它打印:

-4101885043414705786563701568963176764603483495211119243453355953219830430011006780068899468997203661787555969981250050126586203424320244681571103387315766489883301796219461838644670607029711305942610787622864198879363376953745160639821663444829839767678538571371627347101810056161000273217639447052410683392.000000

我究竟做错了什么?代码将两个参数推送到printf()然后调用它.没什么复杂的.


更新:我认为我修复了这个问题还为时过早.我已经更新了代码.

Chr*_*odd 5

该指令push f_0在堆栈中推送f_0的地址,而不是内存中的5.5,所以printf例程将获取地址,加上保存的ebp(堆栈中的下4个字节)并将这些位解释为double并打印出来出.如你所见,这是一个非常大的数字.

您需要加载8个字节f_0并推送它们.就像是

move eax, f_0
push dword ptr [eax+4]
push dword ptr [eax]
Run Code Online (Sandbox Code Playgroud)

编辑

您需要按8个字节,因为fp64值是8个字节.fp64就是printf知道如何打印的 - 事实上fp64就是C知道如何传递给函数或进行操作.fp32值只能从内存加载并存储到内存中,但在操作之前总是隐式转换为fp64(或更大).如果要加载fp32值,将其转换为fp64,并将其推入堆栈,即可使用

fld dword ptr [f_0]
sub esp, 8
fstp qword ptr [esp]
Run Code Online (Sandbox Code Playgroud)

这实际上加载了一个fp32值并将其转换为fp80(x87的内部格式),然后将该fp80值转换为fp64并将其存储在堆栈中.

  • George:我很确定`printf`没有标准化的方法来打印`float`,因为C会自动将`float`参数转换为`double`.你可以编译`float f = 5.5; printf("%f",f);`并反汇编对象代码,看看会发生什么. (2认同)