7

test.exe通常はスタンドアロン アプリケーションとして使用されるという名前の exe があります。この exe を別のアプリケーション app.exe 内のモジュール (dll) として使用したいと考えています。

test.exe のコードは、次のような非常に単純なことを行います。

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

どこsomeMethod()が virtual で、MyClass には virtual d'tor があります。
doTest()は test.exe からエクスポートされ、test.lib という名前のライブラリが作成され
ます。app.exe はこのライブラリとリンクされ、起動時に test.exe を静的にロードします。

test.exe をスタンドアロンで実行しているときは問題なく動作しますが、app.exe 内からロードして実行しているときはクラッシュします。
デバッガーでコードにステップ インすると、仮想メソッドの呼び出しでクラッシュが発生していることが明らかになりました。vftable がどういうわけか悪くなることがわかりました。

いくつかの調査の後、MyClass のコンストラクター内のコードが実行されている場合、vftable は 1 つのことですが、呼び出しがnew返されると、「ローカル vftable」と呼ばれる別のものに置き換えられることがわかりました。なぜこれが.

約 1 日デバッグした後、この「ローカル vftable」のポインターは、test.exe がスタンドアロンの場合とモジュールとしてロードされた場合の両方の場合で同じであることがわかりました。test.exe が別のアドレスに読み込まれるため、これは正しくありません...
この理論をテストするために、リンカ オプションの読み込みアドレスを、app.exe にあるときに test.exe が読み込まれるアドレスに変更しました。 、見よ、すべてが機能します。

明らかに、これは恒久的な解決策ではありません。次回、このランダムに選択されたアドレスが占有され、同じ問題が再び発生する可能性があるからです。

私の質問: この「ローカル vftable」が exe の静的読み込みアドレスに関連付けられているのはなぜですか? exeをモジュールとしてロードするのは悪いことですか? exe が静的アドレスにロードされていると想定するのはなぜですか?

参考までに、これはすべて MSVC 2008、Windows XP x64 で行われます。

4

2 に答える 2

4

通常、再配置可能である必要がないため、VC++ はデフォルトで .exe から再配置情報を取り除きます。

/fixed:no を使用すると、再配置情報を保持するように強制できます。参照: http://msdn.microsoft.com/en-us/library/w368ysh2.aspx

于 2009-12-08T09:52:44.977 に答える
4

私が最終的に使用した回避策は、コンパイル構成を追加し、exeを実際のdllとして強制的に動作させるのではなく、実際のdllとしてコンパイルすることです。

を使用/fixed:noしても、何らかの理由で問題が解決しませんでした。

exe と DLL のもう 1 つの違いは、エントリ ポイントが異なることです。DLL のエントリ ポイントは DllMain であり、exe は最終的に main() または WinMain() を呼び出す CRT にエントリ ポイントがあります。

于 2009-12-08T11:02:21.300 に答える