在 GNU 汇编器中,$
指定一个文字值(编码到指令中的值)。标签的值是它的地址。所以$x
, $format
, $result
, 和$text
是这些标签的地址;它们是您拥有要标记的值的地址。printf
不使用地址%f
。您必须传递浮点数的值,而不是其地址。而且,正如 Frank Kotler 所指出的,您必须将其作为 64-bit 传递double
,而不是 32-bit传递float
。
执行此操作的最简单方法可能是在指令之前插入add $-8, %esp
(或add %esp, $-8
,取决于汇编器版本中操作数的顺序)并将FSTS result
指令更改FSTS result
为FST (%esp)
or FSTL (%esp)
,具体取决于您的汇编器。(此外,这些可能是FSTP (%esp)
或FSTPL (%esp)
从浮点堆栈中弹出值,而不是将其保留在那里。)然后删除push $result
.
这些更改将在堆栈上分配八个字节(在add
指令中)并将浮点结果存储到这八个字节中。
另外,我希望您的代码负责清理传递给被调用例程的参数:它应该在调用scanf
弹出两个参数后向堆栈指针添加 8,它应该在调用后添加 12printf
以弹出新的八字节参数和格式字符串的四字节地址。您的程序可以在没有这些更改的情况下运行,因为您通过调用exit
. ret
但是,如果不清理堆栈,就不可能从带有指令的例程返回。
补充
以下代码适用于ideone.com,使用 Assembler (gcc-4.7.2) 的第二选择:
.text
text: .asciz "Function result: %4.2f \n"
.data
x: .float 2.0
one: .float 1.0
result: .float 0.0
format: .asciz "%f"
.global main
main:
push $x
push $format
call scanf
add $8, %esp
FINIT
FLDS x
FMULS x #x*x
FADDS one
FSQRT
FSUB one
add $-8, %esp
FSTPL (%esp)
xor %eax, %eax
push $text
call printf
add $12, %esp
pushl $0
call exit