Assembly 如何从程序集打印浮点数?
我试图通过调用Assembly 如何从程序集打印浮点数?,assembly,printf,gnu-assembler,att,fpu,Assembly,Printf,Gnu Assembler,Att,Fpu,我试图通过调用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 _star
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
到
关于代码的其他一些备注:
- 如果可能,使用相对寻址模式而不是绝对寻址模式。具体来说,这意味着用内存操作数中的
替换foo(%rip)
,包括foo
learesult(%rip),%rdi
- 请确保在函数末尾保留一个干净的x87堆栈,否则其他代码可能会错误地导致它溢出。例如,使用
存储结果并将其从堆栈中弹出fstplpi(%rip)
- 使用
,而不是movsd
将一个双精度数据加载到SSE寄存器中,而不是一对movupd
- 考虑使用SSE而不是x87,如果可能的话。这是在x86-64中进行标量FP运算的标准方法,这就是为什么XMM寄存器是调用约定的一部分。(除非需要80位扩展精度,但内存中有一个
常量,其精度远远低于x87pi
)fldpi
pi
的至少32位进行了操作。打印时,这些位的精度不足以影响显示的值。movupd
加载16个字节,但您只有一个.double
。使用movsd
。另外,您不应该存储到value
而不是覆盖pi
常量吗?此外,如果您坚持使用传统x87,请使用fldpi
获得更精确的pi常数。此外,标准调用约定传递RDI中的第一个参数,而不是RBX。你的区域函数太奇怪了。@PeterCordes非常感谢这个函数只是为了测试,所以我没有注意太多细节,但是为什么移动16个字节似乎没有引起任何问题,即使在.data
部分中更改定义pi
变量的顺序,除非它是未映射页面前的最后8个字节,事实上,这并不是错误。但是,如果你链接到其他文件,这些文件也会放入.data。在XMM寄存器中接受double
arg的函数不关心寄存器的上半部分是否为零。加载高一半通常效率很低(8字节存储后存储转发暂停,可能还有缓存线拆分,在旧CPU上movupd
天生比movsd
甚至movapd
慢)@KhaledGaber,仅仅因为它现在似乎没有引起任何问题并不意味着它是正确的。错误的代码只有在您最不期望的时候才会显示出它的缺陷。
fmull pi # multiply r^2 by pi
fstl pi # Store result to pi
...
cvtsi2sd %rbx, %xmm0
mulsd pi(%rip), %xmm0
ret