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

Mat*_*nes 2 c x86 assembly 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
Run Code Online (Sandbox Code Playgroud)

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);

}
Run Code Online (Sandbox Code Playgroud)

我输入的华氏温度为摄氏212.0,因此摄氏输出为100,我的摄氏温度转换为华氏30.0,因此华氏温度的结果应为86。

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

Dan*_*zar 5

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

extern "C" double fahrentocel(double temp);
extern "C" double celtofahren(double temp);
Run Code Online (Sandbox Code Playgroud)

这两个函数都接受double参数并返回double结果。关于接口,这很好,但是您的实现则相反celtofahren

fild real8 ptr [ebp+8] ; load c
Run Code Online (Sandbox Code Playgroud)

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

其次,您将错误的格式参数传递给printf,该参数f应用于double值- d用于整数。从而,

printf("%d", output);
Run Code Online (Sandbox Code Playgroud)

应该成为

printf("%f", output);
Run Code Online (Sandbox Code Playgroud)