【问题标题】:How to properly return a double in linux asm如何在 linux asm 中正确返回双精度值
【发布时间】:2019-08-07 17:37:14
【问题描述】:

当我调用该函数时,它返回 0.0000,而它应该返回 25.0000

我曾尝试寻找类似的问题,但找不到。我试过翻阅英特尔的手册,但到目前为止没有任何效果。

我通过c++调用函数

   double t=floatingPointTest(5);
   printf("%f\n",t);

asm 函数:

floatingPointTest:
        push    rbx
        push    rbp
        mov     rbp,rsp

        cvtsi2sd    xmm0,rdi
        cvtsi2sd    xmm1,rdi
        mulsd       xmm0,xmm1

        mov     rsp,rbp
        pop     rbp
        pop     rbx
        ret

即使 rdi 为 5,我也得到 0.0000

【问题讨论】:

  • 在调试器中单步执行?
  • 确实,似乎 cvtss2sd xmm0,xm​​m0 就在通话之后。知道为什么吗?
  • C 代码中floatingPointTest 的原型是什么?
  • 这里有两种可能。您已将floatingPointTest 的原型定义为返回float 而不是double 和/或floatingPointTest 的第一个参数是错误的。您的汇编代码建议您的函数采用 C long(64 位 GCC 中的四字)并返回双精度。正确的原型是extern double floatingPointTest(long val);
  • 如果答案解决了您的问题,请考虑通过接受答案将其标记为已解决。可以在这里找到这样做的方法和原因:meta.stackexchange.com/a/5235/271768

标签: c++ linux assembly floating-point x86-64


【解决方案1】:

您没有向我们展示关键信息 - 您使用的函数 floatingPointTestC++ 原型是什么。有几件事可能会导致这种行为。

  • 您声明 floatingPointTest 以将 floatdouble 作为函数的第一个参数,而它应该是一个整数。您的汇编代码使用此指令:

    cvtsi2sd    xmm0,rdi
    

    我们可以推断出第一个参数(在 RDI 中)应该是带符号的 long,因为您使用 RDI 作为源操作数并且因为 cvtsi2sd 带有64 位寄存器会将带符号的四字整数从 64 位寄存器转换为目标 XMM 寄存器中的双精度浮点值。

  • 您的原型被声明为返回类型为float,而不是double。由于您的汇编代码仅将数学作为标量双打,您需要从函数返回 double

C++ 的正确原型可以写成:

extern "C" double floatingPointTest(long val);

观察

您的代码不使用 RBX,因此无需保存/恢复它。您实际上并不需要堆栈帧,您可以通过将与源和目标相同的寄存器传递给mulsd 来乘以一个数字。这段代码会做同样的事情:

floatingPointTest:
        cvtsi2sd    xmm0, rdi
        mulsd       xmm0, xmm0
        ret

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多