为什么我在 MASM 汇编中使用 FPU x87 指令集执行操作时得到无意义的数字?
Why am I getting nonsensical numbers when performing operations with the FPU x87 instruction set in MASM Assembly?
最近开始学习汇编,正在学习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
参数和 return 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);
最近开始学习汇编,正在学习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
参数和 return 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);