c - 为什么在 MASM Assembly 中使用 FPU x87 指令集执行操作时会得到无意义的数字?

标签 c assembly x86 masm fpu

我最近开始学习汇编,现在正在学习 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。我没有收到任何错误代码,因此该函数似乎执行时没有异常,这告诉我这可能是我编写代码的方式的逻辑错误。

最佳答案

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

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

这两个函数都采用 double 参数并返回 double 结果。对于接口(interface)来说这很好,但是您的 celtofahren 实现则不然:

fild real8 ptr [ebp+8] ; load c

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

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

printf("%d", output);

应该变成

printf("%f", output);

关于c - 为什么在 MASM Assembly 中使用 FPU x87 指令集执行操作时会得到无意义的数字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57436864/

相关文章:

c - 二进制启动后立即出现段错误

c - 矩阵与 vector 相乘

c - 访问全局变量给出垃圾值

linux - NASM 一次打印一个字符

python - 如何写入 LLDB 中的 XMM 寄存器

assembly - printf 在 x86-64 上是否需要额外的堆栈空间?

c - 如何判断字典中是否包含某个值?

c - 如何在 C 中生成新函数?

assembly - 如何创建一个扩展为 "(x+y*240)*2"之类的表达式的 GNU GAS 宏?

c - 机器指令中 exit(0) 时为 "Access violation reading"?