在c ++代码中使用FPU返回值 [英] Using FPU return values in c++ code

查看:140
本文介绍了在c ++代码中使用FPU返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个x86 NASM 程序,它似乎工作完美。我有问题使用从它返回的值。这是使用MSVC ++的32位Windows。我希望在 ST0 中返回值。

I have an x86 NASM program which seems to work perfectly. I have problems using the values returned from it. This is 32-Bit Windows using MSVC++. I expect the return value in ST0.

一个最小的例子演示了返回值的问题可以在这个C ++和 NASM 装配代码:

A minimal example demonstrating the problem with the returned values can be seen in this C++ and NASM assembly code:

#include <iostream>
extern "C" float arsinh(float);

int main()
{
    float test = arsinh(5.0);
    printf("%f\n", test);                    
    printf("%f\n", arsinh(5.0));             
    std::cout << test << std::endl;          
    std::cout << arsinh(5.0) << std::endl;   
}

装配代码:

section .data
value: dq 1.0
section .text
global _arsinh
_arsinh:
    fld dword[esi-8]      ;loads the given value into st0
    ret

使用返回值虽然,因为我总是得到错误的值,无论我使用的数据类型。在这个例子中,应该返回值5,我希望输出如下:

I can't figure out how to use the return value though, as I always get the wrong value no matter which data type I use. In this example the value 5 should be returned and I'd expect output like:


5.000000

5.000000

5.000000

5

5

而我得到的输出类似于:

Instead I get output similar to:


-9671494178951383518019584.000000

-9671494178951383518019584.000000

-9671494178951383518019584.000000

-9671494178951383518019584.000000

-9.67149e + 24

-9.67149e+24

5

只有最终值显示正确。这个代码有什么问题?为什么不总是返回我期望从我的函数的浮点值?如何修复此代码?

Only the final value appears to be correct. What is wrong with this code? Why doesn't it always return the floating point value I am expecting from my function? How can I fix this code?

推荐答案

主要的问题不是有一个失败返回值在浮点寄存器 ST0 ,但是在尝试从堆栈加载32位(单精度)float参数的方式。问题在这里:

The primary issue is not that there is a failure returning a value in floating point register ST0, but in the way you attempt to load the 32-bit (single precision) float parameter from the stack. The issue is here:

fld dword[esi-8]      ;loads the given value into st0

这应该是:

fld dword[esp+4]      ;loads the DWORD parameter from stack into st0

fld dword [esi-8] 只能工作,因为调用函数在内部使用 ESI 。使用不同的 C 编译器和优化,您可能会发现代码无法完全工作。

fld dword[esi-8] only works sometimes because of the way the calling function uses ESI internally. With different C compilers and optimizations enabled you may find the code fails to work altogether.

使用32位C / C ++代码参数在堆栈上从右到左。当在32位代码中执行 CALL 指令时,4字节返回地址被放置在堆栈上。内存地址 esp + 0 将包含返回地址,第一个参数将位于 esp + 4 。如果你有第二个参数,它将在 esp + 8 。在此 CDECL 调用约定的详细说明=nofollow> WikiBook条目。重要性:

With 32-bit C/C++ code parameters are passed on the stack from right to left. When you do a CALL instruction in 32-bit code the 4 byte return address is placed on the stack. Memory address esp+0 would contain the return address and the first parameter would be at esp+4. If you had a second parameter it would be at esp+8. A good description of the Microsoft 32-bit CDECL calling convention can be found in this WikiBook entry. Of importance:



  • 函数参数以从右到左的顺序传递到堆栈。 li>
  • 函数结果存储在EAX / AX / AL

  • 浮点返回值将在ST0中返回

  • 8位和16位整数参数提升为32位参数。

对于x87 FPU指令,非常重要的是,当返回 FLOAT 时,堆栈上的唯一值是 ST0 中的值。不能释放(弹出/释放)任何其他你放在FPU堆栈可能导致您的函数失败时调用多次。 x87 FPU堆栈只有8个插槽(不是很多)。如果在函数返回之前不清除FPU堆栈,当未来指令需要在FPU堆栈上加载新值时,可能导致FPU堆栈溢出。

When dealing with x87 FPU instructions it is very important that the only value on the stack when returning a FLOAT is the value in ST0. Failure to release(popping/freeing) anything else you put on the FPU stack can lead to your function failing when called multiple times. The x87 FPU stack only has 8 slots (not very many). If you don't clean off the FPU stack before the function returns, can lead to FPU stack overflows when future instructions need to load a new value on the FPU stack.

您的函数的示例实现可能如下所示:

An example implementation of your function could have looked like:

use32
section .text
; _arsinh takes a single float (angle) as a parameter
;     angle is at memory location esp+4 on the stack
;     arcsinh(x) = ln(x + sqrt(x^2+1)) 
global _arsinh
_arsinh:
    fldln2           ; st(0) = ln2
    fld dword[esp+4] ; st(0) = angle, st(1)=ln2
    fld st0          ; st(0) = angle, st(1) = angle, st(2)=ln2
    fmul st0         ; st(0) = angle^2, st(1) = angle, st(2)=ln2
    fld1             ; st(0) = 1, st(1) = angle^2, st(2) = angle, st(3)=ln2
    faddp            ; st(0) = 1 + angle^2, st(1) = angle, st(2)=ln2
    fsqrt            ; st(0) = sqrt(1 + angle^2), st(1) = angle, st(2)=ln2
    faddp            ; st(0) = sqrt(1 + angle^2) + angle, st(1)=ln2
    fyl2x            ; st(0) = log2(sqrt(1 + angle^2) + angle)*ln2
                     ; st(0) = asinh(angle)
    ret

这篇关于在c ++代码中使用FPU返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆