2

在过去的几天里,我在玩 C++、ASM 和内联 ASM。我知道如何访问内存中的基本变量和类似的东西。现在我正在尝试在 ASM 中使用浮点数。我已经反汇编了这段代码:

float A = 0.058;

我有这个结果:

 fld         dword ptr ds:[00415744h]  
 fstp        dword ptr [ebp-8]

但我不明白这段代码。我在谷歌上搜索,但我没有找到任何对我有用的东西。任何人都可以向我解释 ASM 中的实数吗?谁能解释我这段代码?请帮我。

4

2 回答 2

4

这是编译器对您的代码所做的:

编译器将“0.058”识别为浮点文字。它分析字符串以计算它表示的值并将该值编码为双精度浮点值。然后它识别出您正在将此双精度值分配给单精度对象(浮点 A,而不是双精度 A),因此它不需要完整的双精度值。因此编译器将其转换为单精度。产生的编码可能是 0x3d6d9168,这是单精度 0.058 的常见 IEEE 754 编码。

在编译器生成的汇编代码中的某处,编译器生成了一个指令(对汇编器的指令),该指令导致该值 0x3d6d9168 存储在内存中。(这是一个复杂的过程;汇编器将值写入它生成的目标文件,作为各种数据的一部分,作为程序映像的一部分。当程序准备好执行或程序执行时,该数据将被加载到内存中首先尝试访问那部分内存。)

此外,编译器生成了 fld 指令“fld dword ptr ds:[00415744h]”。自从我使用这种形式的汇编以来已经有一段时间了,所以我可能有点偏离,但我相信指令说“使用数据段 (DS) 寄存器作为基地址,使用 0x415744 作为段内的偏移量。该组合是指向双字的指针。从那里加载四个字节到浮点堆栈。(浮点堆栈是处理器内部的一组特殊寄存器。)

fstp 指令“fstp dword ptr [ebp-8]”的意思是“将扩展基指针 (EBP) 寄存器的内容减去 8。该值是指向双字的指针。将浮点堆栈中的四个字节存储到该双字中,然后将项从浮点堆栈中弹出。”</p>

请注意,0x415744 与浮点值无关。它是存储常量值的内存地址。这两条指令从内存中的只读位置加载常量值并将其存储到 [ebp-8],这是编译器决定将值保留在变量 A 中的内存位置。EBP 通常是用于引用堆栈中的位置,因此编译器几乎肯定会在此函数的堆栈帧中留出一些内存来保存变量的值。

我怀疑您在关闭优化的情况下编译了此代码。打开优化后,编译器可能不会费心将浮点值实际存储在分配给 A 的内存中。这是因为您没有立即对该值执行任何操作,只是将其存储在 A 中。但我们已经知道值并将其存储在其他地方,那么为什么还要复制它呢?相反,在代码中稍后的某个位置,您实际使用 A 的值时,编译器将从只读内存中加载它并直接在计算中使用它。(情况并非总是如此;您可以编写需要编译器进行一些复制的代码,因为您的代码可能会采用多个可能路径之一,具体取决于传递给它的参数或其他因素,并且编译器需要进行复制以确保将正确的数据用于所遵循的路径。但是,一般来说,您不应期望在您编写的 C 代码和编译器生成的汇编指令之间找到完全匹配。)

于 2012-06-25T16:22:43.860 回答
2

第一行将常量浮点值 0.058 加载到 FPU 堆栈。第二行将 FPU 堆栈的顶部复制到 CPU 堆栈,由 ebp-8 寻址。

您可以在此处阅读有关 FPU 的说明:http ://maven.smith.edu/~thiebaut/ArtOfAssembly/CH14/CH14-4.html或任何其他大会参考。

编辑。

dword ptr [ebp-8] 将 FPU 堆栈的顶部复制到堆栈上的 DWORD 大小的局部变量。来自汇编参考,EBP(基指针):汇编函数将基指针设置为等于堆栈指针,然后将其自己的内部变量放在堆栈上。从那时起,函数引用其参数和变量相对于基指针而不是堆栈指针。

于 2012-06-24T12:41:22.837 回答