我正在使用_declspec(dllexport)从C++ exe导出一个函数。该函数在由exe本身调用时运行良好。我正在从另一个测试项目的exe加载这个exe (让我们调用这个exe1) --我将使用静态链接来调用这个exe2,也就是说,我在编译exe2时使用exe 1的.lib文件,exe2在启动时将它加载到内存中,就像任何dll一样。这会导致函数在执行中失败。
在函数内的开关case语句的反汇编中揭示了确切的问题。
exe1调用该函数时的汇编代码
switch (dwType)
0040FF84 mov eax,dword ptr [dwType]
0040FF87 mov dword ptr [ebp-4],eax
0040FF8A cmp dword ptr [ebp-4],0Bh
0040FF8E ja $LN2+7 (40FFD2h)
0040FF90 mov ecx,dword ptr [ebp-4]
0040FF93 jmp dword ptr (40FFE0h)[ecx*4] 考虑最后两条指令。mov将传递的in参数移动到ecx中。在40EFF0h,我们为各自的case语句提供了各种指令的地址。因此,jmp会带我们去看相关的案例说明。
exe2调用该函数时的汇编代码
switch (dwType)
0037FF84 mov eax,dword ptr [dwType]
0037FF87 mov dword ptr [ebp-4],eax
0037FF8A cmp dword ptr [ebp-4],0Bh
0037FF8E ja $LN2+7 (37FFD2h)
0037FF90 mov ecx,dword ptr [ebp-4]
0037FF93 jmp dword ptr [ecx*4+40FFE0h]发现出什么问题了吗?指令地址。代码现在已加载到内存中的另一个位置。编译exe1时,编译器假定我们将始终启动它,因此它总是在0x0040000加载,就像所有windows exe1的情况一样。因此,它将一些像40FFE0h这样的值硬编码到指令中。只有在第二种情况下,40FFE0与垃圾内存一样好,因为我们要查找的指令地址表不在那里。
如何在不将exe1转换为dll的情况下解决这个问题?
发布于 2010-01-12 11:09:00
别这么做。这不值得你费心。
我一段时间前就试着做你想做的事。您可以通过更改属性窗口中“Linker->Advenced>”下的选项来解决不可重定位的exe问题,但是接下来您还会遇到其他问题。
最后让我意识到这是浪费时间的是认识到EXE没有DllMain()函数。这意味着CRT库没有被初始化,所有的东西都不像你期望的那样工作。
发布于 2010-01-12 11:09:58
你考虑过另一种方法吗?例如,将第二个.exe变成一个.dll,并在要将它用作可执行文件时使用rundll32调用它?
否则:生成的程序集很好。问题是,Win32可移植可执行文件有一个基地址(本例中为0x0040000)和一个包含详细地址位置的部分,以便在需要时可以重新基于它们。
因此,每两件事中就有一件事情发生了:--编译器在构建IMAGE_BASE_RELOCATION时要么不包括.exe记录。-或者运行时在动态加载.exe时没有执行基本的重定位-(可能是两者兼而有之)
如果.exe包含重新定位记录,则可以自己读取这些记录并执行基本重新定位。您将不得不跳过循环,例如确保您有对内存的写访问权限(VirtualAlloc等)。但这在概念上很简单。
如果.exe不包含重新定位记录,那么您将被填充--要么找一个编译器选项来强制它们包含,要么找到另一种方法来完成您正在做的事情。
编辑:正如shoosh指出的,一旦您修复了这个问题,您可能会遇到其他问题。
https://stackoverflow.com/questions/2048301
复制相似问题