Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 如何从程序集打印浮点数?_Assembly_Printf_Gnu Assembler_Att_Fpu - Fatal编程技术网

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
    ,而不是
    movupd
    将一个双精度数据加载到SSE寄存器中,而不是一对

  • 考虑使用SSE而不是x87,如果可能的话。这是在x86-64中进行标量FP运算的标准方法,这就是为什么XMM寄存器是调用约定的一部分。(除非需要80位扩展精度,但内存中有一个
    pi
    常量,其精度远远低于x87
    fldpi


它现在起作用了,非常感谢,但我很好奇为什么它只是回显pi值,而不是查看存储在较低32位pi中的任何值。@Khaledgeaber通过单精度操作,只对
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