7

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

test.exe 中的代码做了一些非常简单的事情,比如:

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

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

当我单独运行 test.exe 时,它​​运行得很好,但是当我从 app.exe 中加载它时,它会崩溃。
使用调试器单步执行代码会发现崩溃是在调用虚拟方法时发生的。事实证明,vftable 不知何故变坏了。

经过一番调查,事实证明,当 MyClass 的构造函数中的代码正在运行时,vftable 是一回事,但是当调用new返回时,它会被称为“本地 vftable”的其他东西替换。我发现这个关于为什么会这样的模糊讨论

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

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

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

只是为了上下文:这一切都是通过 MSVC 2008、Windows XP x64 完成的。

4

2 回答 2

4

VC++ 默认从 .exe 中去除 reloc 信息,因为通常它们不需要是可重定位的。

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

于 2009-12-08T09:52:44.977 回答
4

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

/fixed:no由于某种原因,使用并没有解决问题。

exe和DLL之间的另一个区别是入口点不同。DLL 的入口点是 DllMain,而 exe 的入口点位于 CRT 中,最终调用 main() 或 WinMain()。

于 2009-12-08T11:02:21.300 回答