将EXE作为DLL加载,本地vftable

时间:2009-12-08 08:55:01

标签: c++ dll exe vtable

我有一个名为test.exe的exe,它通常用作独立的应用程序。我想在另一个应用程序app.exe中使用这个exe作为模块(一个dll)。

test.exe中的代码非常简单:

void doTest()
{
    MyClass *inst = new MyClass();
    inst->someMethod();
}

someMethod()是虚拟的,MyClass有虚拟的。
从test.exe导出doTest(),因此创建了一个名为test.lib的库 app.exe与此lib链接,以便在启动时静态加载test.exe。

当我运行test.exe时,它运行得很好但是当我从app.exe中运行它时它会崩溃。
使用调试器进入代码后发现崩溃是在对虚方法的调用中。事实证明,vftable不知何故变坏了。

经过一些调查后发现,当MyClass的构造函数中的代码正在运行时,vftable是一回事,但是当对new的调用返回时,它被替换为其他名为“local vftable”的东西。我找到了this obscure discussion about why this is

经过大约一天的调试后,我发现这个“本地vftable”中的指针在两种情况下是相同的,当test.exe是独立的并且当它作为模块加载时。这可能不对,因为test.exe被加载到不同的地址...
为了测试这个理论,我将链接器选项中的加载地址更改为app.exe在app.exe中加载的地址,现在,请注意,一切正常。

显然,这不是一个永久的解决方案,因为下次这个随机选择的地址可能会被占用,同样的问题会再次出现。

所以我的问题:为什么这个“本地vftable”绑定到exe的静态加载地址?将exe作为模块加载是一件坏事吗?为什么exe假设它被加载到它的静态地址?

仅供上下文:这些都是使用MSVC 2008,Windows XP x64完成的。

2 个答案:

答案 0 :(得分:4)

VC ++默认从.exes中删除reloc信息,因为它们通常不需要重定位。

您可以强制它使用/ fixed:no保留reloc信息。请参阅:http://msdn.microsoft.com/en-us/library/w368ysh2.aspx

答案 1 :(得分:4)

我最终使用的解决方法是简单地添加一个编译配置并将exe编译为一个真正的dll,而不是强迫它像一个一样。

使用/fixed:no由于某种原因无法解决问题。

exes和DLL之间的另一个区别是入口点不同。 DLL的入口点是DllMain,其中作为exe的入口点在CRT中最终调用main()或WinMain()。