C++ 在 64 位 Windows 7 和 32 位 Windows XP 上使用 Visual Studio C++ 2010 Express 编译(来自同一源)DLL。Windows 7 上的外部 64 位应用程序调用 DLL 并正确执行。Windows XP 上的等效 32 位应用程序在从 DLL 调用返回时会出现堆栈或内存损坏。
尝试对此进行调试时,我在 DLL 将数据从某些内部结构复制到外部应用程序想要的位置处设置了一个断点,这是返回前的最后一步。在给定的点上,我在 Visual Studio 中查看类似这样的内容:destination[i].field = source[i].field; 其中源和目标中的两个字段都是双精度或长整数。
将鼠标悬停在源上会显示正确计算的值。在执行语句之前将鼠标悬停在目标上,表明它已正确初始化为零。执行语句后,目标包含不同的值,例如 36.3468 变为 0.00104800000000122891,6 变为 10,等等。
这很奇怪。也许存在结构元素错位,但这不会在其他地方显示为警告吗?也许我正在跨过内存(仅在 32 位版本中!?),但是在跨过分配之后,值不应该是明显正确的吗?有一段时间没有进入机器代码并且不太了解 x86/x86_64 程序集,我是否必须这样做才能查看执行该分配的代码真正在做什么?
这是似乎无法正确执行的行之一,以及 64 位和 32 位版本中的反汇编,按此顺序:
destination[i].field = source[i].field;
000007FEEF6B4DD3 movsxd rax,dword ptr [i]
000007FEEF6B4DDB imul rax,rax,4A68h
000007FEEF6B4DE2 movsxd rcx,dword ptr [i]
000007FEEF6B4DEA imul rcx,rcx,30h
000007FEEF6B4DEE mov rdx,qword ptr [destination]
000007FEEF6B4DF3 mov r8,qword ptr [source]
000007FEEF6B4DF8 movsd xmm0,mmword ptr [r8+rax+4A40h]
000007FEEF6B4E02 movsd mmword ptr [rdx+rcx+8],xmm0
destination[i].field = source[i].field;
09E64361 mov eax,dword ptr [i]
09E64364 imul eax,eax,4A38h
09E6436A mov ecx,dword ptr [i]
09E6436D imul ecx,ecx,2Ch
09E64370 mov edx,dword ptr [destination]
09E64373 mov esi,dword ptr [source]
09E64376 fld qword ptr [esi+eax+4A10h]
09E6437D fstp qword ptr [edx+ecx+4]
如果我在 64 位版本中跨过该行,VS 会向我显示destination[i].field 的正确值,但在 32 位版本中不会。似乎结构在不同版本中具有不同的大小,因此在最后一次分配中具有不同的偏移量和 4 对 8 个字节,但那时 VS 不应该向我显示正确的值吗?
如果我跳过 32 位版本的 fld 指令,我可以看到 st0 加载了错误的值,即不是为 source[i].field 显示的值,对于 i=0, eax=0, esi=source ,因此可能 4A10h 偏移量是错误的和/或在代码中以不同方式计算以及 VS 使用什么来向我显示该值。这怎么可能?