问题描述
我试图通过调用 printf
来打印一个浮点数,但它似乎总是只打印 pi 值 (3.1415) 尽管结果应该是圆的面积,计算后应该移动到pi变量中。
.section .data
value:
.quad 0
result:
.asciz "The result is %lf \n"
pi:
.double 3.14159
.section .bss
.section .text
.globl _start
.type area,@function
area:
nop
imulq %rbx,%rbx
movq %rbx,value
fildq value
fmul pi # multiply r^2 by pi
fst pi # Store result to pi
movupd pi,%xmm0 # move result to xmm0
nop
ret
_start:
nop
movq $2,%rbx
call area # calculate for radius 2
leaq result,%rdi
movq $1,%rax # specify only one float value
call printf
movq $0,%rdi # Exit
call exit
nop
我总是能得到 3.1415 的回报。我不知道为什么,因为它应该被 fst
指令覆盖。
解决方法
如果浮点运算碰巧使用内存操作数,则需要为浮点运算添加大小后缀。否则,GNU 汇编器将隐式使用单精度,这不是您想要的。要修复您的代码,请更改
fmul pi # multiply r^2 by pi
fst pi # Store result to pi
到
fmull pi # multiply r^2 by pi
fstl pi # Store result to pi
关于您的代码的其他一些说明:
-
尽可能使用
rip
-相对寻址模式而不是绝对寻址模式。具体来说,这意味着在您的内存操作数中用foo
替换foo(%rip)
,包括lea result(%rip),%rdi
-
确保在函数的末尾留下一个干净的 x87 堆栈,否则其他代码可能会虚假地导致它溢出。例如,使用
fstpl pi(%rip)
存储结果并将其从堆栈中弹出。 -
使用
movsd
而不是movupd
将一个双精度值加载到 SSE 寄存器中,而不是一对。 -
如果可能的话,考虑使用 SSE 而不是 x87 来处理所有的数学运算。这是在 x86-64 中进行标量 FP 数学的标准方法,这就是为什么 XMM 寄存器是调用约定的一部分。 (除非您需要 80 位扩展精度,但您在内存中有一个
pi
常量,其精度远低于 x87fldpi
。)... cvtsi2sd %rbx,%xmm0 mulsd pi(%rip),%xmm0 ret