在过去的几天里,我正在玩C ++,ASM和内联ASM。我知道如何访问内存和类似的东西中的基本变量。现在我正在尝试使用ASM中的浮点数。 我已经反汇编了这段代码:
float A = 0.058;
我有这个结果:
fld dword ptr ds:[00415744h]
fstp dword ptr [ebp-8]
但我不明白这段代码。我在谷歌搜索,但我没有找到任何可用的东西。任何人都可以在ASM中解释我的实数,有人能解释一下这段代码吗?请帮帮我。
答案 0 :(得分:4)
这是编译器对您的代码所做的事情:
编译器将“0.058”识别为浮点字面值。它分析了字符串以计算它表示的值,并将该值编码为双精度浮点值。然后它识别出你将这个双精度值赋给单精度对象(float A,而不是double A),所以它不需要完整的双精度值。因此编译器将其转换为单精度。产生的编码可能是0x3d6d9168,这是单精度的.058的常见IEEE 754编码。
编译器生成的汇编代码中的某处,编译器生成一个指令(汇编器的指令),该指令将该值0x3d6d9168存储在内存中。 (这是一个复杂的过程;汇编程序将值写入它生成的目标文件,作为程序图像一部分的各种数据的一部分。当程序准备执行或程序时,该数据将被加载到内存中首先尝试访问该部分内存。)
另外,编译器生成fld指令“fld dword ptr ds:[00415744h]”。自从我使用这种汇编形式以来已经有一段时间了,所以我可能会稍微偏离,但我相信该指令说“使用数据段(DS)寄存器作为基址,0x415744作为段内的偏移量。该组合是指向双字的指针。从那里加载四个字节到浮点堆栈。 (浮点堆栈是处理器内部的一组特殊寄存器。)
fstp指令“fstp dword ptr [ebp-8]”,表示“获取扩展基指针(EBP)寄存器的内容并减去8.该值是指向双字的指针。将浮点堆栈中的四个字节存储到该双字,并将该项目从浮点堆栈中弹出。“
请注意,0x415744与浮点值无关。它是存储器中存储常量值的地址。这两条指令从内存中的只读位置加载常量值并将其存储到[ebp-8],这是内存中编译器决定将值保存在变量A中的位置.EBP通常是用于引用堆栈中的位置,因此编译器几乎肯定会在此函数的堆栈帧中留出一些内存来保存变量的值。
我怀疑你在关闭优化的情况下编译了这段代码。当打开优化时,编译器可能不会费心将浮点值实际存储在为A分配的内存中。这是因为您没有立即对该值执行任何操作,只是将其存储在A中。但我们已经知道了价值并将其存储在其他地方,为什么还要复制呢?相反,在代码中的某个稍后位置,您实际使用A的值,然后编译器将从只读内存加载它并直接在计算中使用它。 (情况并非总是如此;您可以编写需要编译器执行某些复制的代码,因为您的代码可能会根据传递给它的参数或其他因素采用多种可能路径之一,并且编译器需要进行复制以确保正确的数据用于所遵循的路径。但是,通常,您不应期望在您编写的C代码和编译器生成的汇编指令之间找到完全匹配。)
答案 1 :(得分: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(基指针):汇编函数将基指针设置为等于堆栈指针,然后将其自己的内部变量放在堆栈上。从那时起,函数引用其相对于基指针的参数和变量,而不是堆栈指针。