【问题标题】:How can I operate with float point numbers in assembly?如何在汇编中使用浮点数进行操作?
【发布时间】:2015-11-15 03:14:40
【问题描述】:

我需要将两个实数从 C (using extern 'C' double (double num1,double num2)) 发送到返回加法的程序集 procedure这些数字。我还不知道该怎么做。

我试过了,但是没有用。

.data

 res dq 0

.code

        procSuma proc num1,num2

           fld num1   ; load num1 and push it onto the fpu stack
           fld num2   ; load num2 and push it onto the fpu stack
           faddp      ; pop two numbers, add them, push sum on the stack
           fstp res   ; pop sum from the stack and store it in res

        procSuma endp
 end

【问题讨论】:

  • “没用”是什么意思?没有编译,没有产生正确的结果,还有什么?
  • Windows 上的调用约定说 st(0) 应该包含双精度的返回值。所以你应该能够完全消除res 变量,摆脱fstp resfaddp 应该将两个值相加并将结果放入st(0),因此您只需要在之后执行ret。由于您将双浮点数传递给 procSuma 您应该将 procSuma proc num1,num2 更改为 procSuma proc num1:REAL8,num2:REAL8 以便 MASM 知道您的两个参数是 REAL8(8 字节)
  • 另一个问题可能是您应该指定 PROC C 而不是 PROC 以便 MASM 使用 C 调用约定设置过程。所以procSuma proc num1:REAL8,num2:REAL8 应该是procSuma proc C num1:REAL8,num2:REAL8
  • 仅供参考,在 2015 年学习 x87 FPU 并没有太大用处。如果你真的想要,有一个很好的教程链接自 the x86 tag wiki。对于新代码,请使用 SSE/SSE2,除非您需要向后兼容古老的 32 位 CPU(例如 Athlon XP 是最后一个支持 SSE2 的 CPU)。 32bit ABI 在st(0) 中返回浮点结果,因此您无法在 32bit 代码中完全避免它,这也是 32bit 很糟糕并且应该被视为过时的另一个原因。
  • @PeterCordes x87 指令集仍然提供扩展双精度格式和 64 位精度的操作,因此在 2015 年非常有用。不过,几乎没有理由从汇编中使用它。

标签: c assembly x86 masm x87


【解决方案1】:

你出错的地方是将原本不包含在函数中的粘贴代码复制到函数中,我相信你是从这里得到的。 Adding floating point/double numbers in assembly

由于汇编代码现在包含在 proc 中,因此不再需要变量来存储结果,因为结果存储在堆栈中的地址 st(0),这将是您的返回值。当调用fstp 时,它会弹出堆栈(提示:末尾的 p),因此存储在 st(0) 的返回值不再有效。删除 fstp 指令将为您提供预期的结果。

代码就是这样一步一步做的。

procSuma proc num1,num2   

       fld num1   ; This pushes num1 onto the stack at the address of st(0)
       fld num2   ; This pushes num2 onto the stack at the address of st(1)
       faddp      ; This multiplies st(1) and st(0), stores the result at st(0), and then pops the variable stored at st(1) off the stack   
       fstp res   ; !REMOVE THIS. This is why you aren't getting the expected result.It pops the variable in st(0) off the stack, which is your return value.

procSuma endp

【讨论】:

  • 欢迎来到 SO。如果您解释为什么结果需要在st(0) 中,而不是他编造的一些随机命名的全局,这将是一个更好的答案。 (即因为 Windows x86 32 位 ABI)。此外,建议在存储后使用fld 重新加载只是令人困惑。
  • 谢谢你,@PeterCordes。这是一个“只是得到它的工作答案”重新加载 res 将是多余的并且货物崇拜。
  • Michael Petch's answer-in-cmets 比这个答案要好得多,因为它解释了他们的原因。这个答案对帮助困惑的新手了解正在发生的事情没有多大帮助,因此对于谷歌搜索出现此问答的其他任何人来说都不是很长期有用。
【解决方案2】:

我假设这是一项要求您使用 x87 FPU 指令的家庭作业。或者,您可以使用 SSE/SSE2 SIMD 指令来执行添加。

C 在 Win32 上调用 (cdecl) 约定要求在 ST(0) 中返回单精度和双精度浮点数(在 FPU 堆栈顶部注册) .由于faddp 将两个数字相加并将结果放在ST(0) 中,这意味着我们不需要任何临时变量来存储结果。然后可以删除这些行

.data
res dq 0

fstp res   ; pop sum from the stack and store it in res

在创建过程时,您应该指定传递参数的大小,以便 MASM 确切知道操作数的大小。为确保您使用双精度值,请将 double 参数标记为 REAL8(8 字节 REALS)。您还应该使用 PROC C 将 PROC 标记为使用 C 调用约定,以便正确设置和寻址堆栈和参数。过程声明应如下所示:

procSuma proc C num1:REAL8,num2:REAL8 

生成的代码可能如下所示:

.model flat, c
.code

        procSuma proc C num1:REAL8,num2:REAL8

           fld num1   ; load num1 and push it onto the fpu stack
           fld num2   ; load num2 and push it onto the fpu stack
           faddp      ; pop two numbers, add them, push sum on the stack.
                      ; result in st(0) (top of FPU stack)
                      ; We return double values in st(0) so nothing to do
                      ; since faddp put our result in st(0)
           ret

        procSuma endp
 end

您可以通过使用 FADD 而不是 FADDP 来减少添加几条指令:

       fld num1   ; load num1 and push it onto the fpu stack
       fadd num2  ; Add ST(0)(num1) to num2 and store result in ST(0).
                  ; We return double values in st(0) so nothing to do
                  ; since fadd put our result in st(0)

【讨论】:

    猜你喜欢
    • 2017-06-22
    • 2012-06-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 2017-02-07
    • 2015-01-06
    • 1970-01-01
    相关资源
    最近更新 更多