首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在c++代码中使用FPU返回值

在c++代码中使用FPU返回值
EN

Stack Overflow用户
提问于 2016-06-16 17:39:20
回答 1查看 1.1K关注 0票数 0

我有一个x86的NASM程序,这似乎是完美的工作。我在使用从中返回的值时遇到了问题。这是使用MSVC++的32位窗口.我期望ST0中的返回值。

在这个C++和NASM程序集代码中可以看到一个演示返回值问题的最小示例:

代码语言:javascript
复制
#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;   
}

装配代码:

代码语言:javascript
复制
section .data
value: dq 1.0
section .text
global _arsinh
_arsinh:
    fld dword[esi-8]      ;loads the given value into st0
    ret

但是,我不知道如何使用返回值,因为无论使用哪种数据类型,我总是得到错误的值。在本例中,应该返回值5,我希望输出如下:

5.000000 5.000000 5 5

相反,我得到的输出类似于:

-9671494178951383519584.000000 -9671494178951383519584.000000 -9.67149e+24 5

只有最终值似乎是正确的。这个代码有什么问题?为什么它不总是从函数中返回我期望的浮点值?我怎样才能修正这段代码?

EN

回答 1

Stack Overflow用户

发布于 2016-06-19 06:54:08

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

代码语言:javascript
复制
fld dword[esi-8]      ;loads the given value into st0

应改为:

代码语言:javascript
复制
fld dword[esp+4]      ;loads the DWORD parameter from stack into st0

fld dword[esi-8]有时只是因为调用函数内部使用ESI的方式而起作用。如果启用了不同的C编译器和优化,您可能会发现代码完全无法工作。

使用32位C/C++,代码参数从右到左在堆栈上传递。当您在32位代码中执行调用指令时,4字节返回地址将放置在堆栈上。内存地址esp+0将包含返回地址,第一个参数将位于esp+4。如果您有第二个参数,那么它将位于esp+8。在此WikiBook条目中可以找到对Microsoft32位CDECL调用约定的良好描述。具有重要意义:

  • 函数参数按从右到左的顺序传递到堆栈上.
  • 函数结果存储在EAX/AX/AL中
  • 浮点返回值将在ST0中返回。
  • 8位和16位整数参数被提升为32位参数.

在处理x87 FPU指令时,非常重要的是,当返回浮点时,堆栈上唯一的值是ST0中的值。未能释放(弹出/释放)您放置在FPU堆栈上的任何其他内容,都可能导致功能多次调用失败。x87 FPU堆栈只有8个槽(不是很多)。如果在函数返回之前不清除FPU堆栈,则可能导致FPU堆栈在以后的指令需要在FPU堆栈上加载新值时溢出。

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

代码语言:javascript
复制
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
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37865951

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档