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。我没有收到任何错误代码,因此该函数似乎毫无例外地执行,这表明我编写代码的方式可能是逻辑错误。
这里有两个问题。根据使用它们的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)