1

我遇到了一个以前从未见过的奇怪问题,在 Delphi 2010 中,有时当使用例程 CopyMemory(内部调用 Move)时,我得到一个 Invalid Float Point Operation 异常,当使用 Move 时可能发生这种情况?

我在汇编程序中有一个调试信息,我检查了 Move 的源代码,问题发生在 FILD 指令中,我发现 FILD 将整数值从内存转换为寄存器中的浮点数,它可能会触发该无效操作,但为什么那个会发生?我已经坚持了 2 天了

Assembler Information:
; System.Move (Line=0 - Offset=1)
;
00404E0C cmp eax, edx
00404E0E jz System.Move
00404E10 cmp ecx, +$20
00404E13 jnbe System.Move
00404E15 sub ecx, +$08
00404E18 jnle System.Move
00404E1A jmp dword ptr [System.Move+ecx*4]
00404E21 fild qword ptr [ecx+eax]
00404E24 fild qword ptr [eax] ; <-- EXCEPTION
00404E26 cmp ecx, +$08
00404E29 jle System.Move
00404E2B fild qword ptr [eax+$08]
00404E2E cmp ecx, +$10
00404E31 jle System.Move
00404E33 fild qword ptr [eax+$10]
00404E36 fistp qword ptr [edx+$10]
00404E39 fistp qword ptr [edx+$08]
00404E3C fistp qword ptr [edx]
00404E3E fistp qword ptr [ecx+edx]

Registers:
EAX: 0E3A4694 EDI: 0000000D
EBX: 00001B5C ESI: 0ECF7928
ECX: 00000005 ESP: 0612FC1C
EDX: 0E3A2B38 EIP: 00404E24

什么可能导致该错误?

4

2 回答 2

6

我以前见过这个问题。问题是在进入 Move 方法之前,x87 寄存器的堆栈包含一些无效的浮点值,而不是为空。这是由于之前发生的异常导致 x87 堆栈这样离开。

Move 命令使用 x87 寄存器,因为它们允许在不依赖 SSE 指令的情况下快速移动数据,但它假定堆栈为空。

寻找解决方案:

  • 在 Move 命令的开始处设置断点并使用 FPU 调试窗口来验证 FPU 堆栈是否确实被丢弃。
  • 从这里开始:回溯在您的应用程序中,使用同一窗口导致此垃圾 FPU 堆栈的原因。这是你的问题的原因。
于 2012-07-06T16:05:12.957 回答
1

Seems similar to a problem I had before: Memory corruption in System.Move due to changed 8087CW mode (png + stretchblt)

My fix was to disable SSE/MMX stuff in FastMove.pas, so it did not (mis)use the FPU anymore (and not vulnerable to FPU corruption)

于 2012-07-06T20:35:41.247 回答