为啥在 MASM 汇编中使用 FPU x87 指令集执行操作时得到无意义的数字?

Posted

技术标签:

【中文标题】为啥在 MASM 汇编中使用 FPU x87 指令集执行操作时得到无意义的数字?【英文标题】:Why am I getting nonsensical numbers when performing operations with the FPU x87 instruction set in MASM Assembly?为什么在 MASM 汇编中使用 FPU x87 指令集执行操作时得到无意义的数字? 【发布时间】:2019-08-09 20:40:27 【问题描述】:

我最近开始学习汇编,现在正在学习 FPU x86 架构和 FPU 堆栈。我有两个简单的函数用于在摄氏和华氏之间进行转换,反之亦然。

我研究了各种不同的指令,尝试了 FPU 指令的变体,包括自动执行 POP 操作的指令,并尝试通过调试器了解我所看到的内容。至今无果。

.386
.model flat, c

.const
  r8_ftoc real8 0.5555555556 ;5/9
  r8_ctof real8 1.8 ;9/5
  i4_32 dword 32
.code
  fahrentocel PROC
    push ebp
    mov ebp, esp
    fld[r8_ftoc]
    fld real8 ptr [ebp+8] ; load f 
    fild[i4_32] ; load 32    
    fsubp
    fmulp
    pop ebp
    ret
  fahrentocel ENDP

  celtofahren PROC
    push ebp
    mov ebp, esp
    fild real8 ptr [ebp+8] ; load c
    fmul[r8_ctof]
    fiadd[i4_32]
    pop ebp
    ret
  celtofahren endp
END

C 代码:

extern "C" double fahrentocel(double temp);
extern "C" double celtofahren(double temp);

int main()

    double celsius = 30.0;
    double fahrenheit = 212.0;
    double output = fahrentocel(fahrenheit);
    printf("%lf", output);


我输入的华氏到摄氏度是212.0,所以摄氏度输出是100,我从摄氏度到华氏度的转换是30.0,所以华氏度的结果应该是86。

但是,对于这两个函数中的每一个,我分别得到 562950 和 858993459。我没有收到任何错误代码,因此该函数似乎毫无例外地执行,这告诉我这可能是我编写代码的方式存在逻辑错误。

【问题讨论】:

我没有看到任何输出函数。您的输出表明您得到SDWORDs 作为输出,但您应该得到DOUBLEs。你确定你的输出函数显示DOUBLEs? 你没有展示任何实际使用这些函数的代码,所以我们只能假设参数的类型是什么。 fahrentocel 函数的参数是double,但celtofahren 的参数似乎是一个整数,因为它加载了fild。这是故意的吗? 请发布生成完整、可编译、可运行程序所需的所有其余代码,即minimal reproducible example。 我已经添加了 C 代码,对此我深表歉意。谢谢你通知我! @fuz %f 是 double,%Lf 是 long double,%lf 是编译器供应商想要的任何东西。 【参考方案1】:

这里有几个问题。根据使用它们的 C 代码中的函数声明,即:

extern "C" double fahrentocel(double temp);
extern "C" double celtofahren(double temp);

这两个函数都采用double 参数并返回double 结果。当涉及到接口时,这很好,但您对celtofahren 的实现另有说明:

fild real8 ptr [ebp+8] ; load c

在这里,您将函数的参数作为整数加载到 FPU 堆栈中,即使您自己指示 C 编译器该函数采用双精度数。因此,C 编译器发出将 double 推送到常规堆栈的代码,但由于 fild 指令,您的程序集将其作为常规整数读取。请注意fahrentocel 正确加载了参数。

其次,您将错误的格式参数传递给printf,对于double 值,它应该是f - d 用于整数。因此,

printf("%d", output);

应该变成

printf("%f", output);

【讨论】:

嘿丹尼尔,我已经设法通过将它打印为整数来修复它,我只是传入整数,所以将它加载为 int 似乎不是问题,但我想如果我用十进制值传递温度,那将是一个问题,谢谢你指出来。以后我会记住您的回答以避免出现问题。十分感谢你的帮助!抱歉,如果这看起来像一个简单的错误,我的 C 非常生锈。

以上是关于为啥在 MASM 汇编中使用 FPU x87 指令集执行操作时得到无意义的数字?的主要内容,如果未能解决你的问题,请参考以下文章

汇编浮点指令

SSE FPU 并行

处理器 增强指令集

处理器 增强指令集

处理器 增强指令集

fpu 状态 (x87)