4

NASMを使用してx86アセンブリでCOMオブジェクトを構築しています。私はCOMを非常によく理解しており、x86アセンブリをかなりよく理解していますが、2つをメッシュ化すると、ハングアップします...(ちなみに、x86アセンブリの使用を思いとどまらせることを考えている場合は、ご遠慮ください。これをx86アセンブリで構築するのには特別な理由があります!)

COMオブジェクトで使用するvtableを作成しようとしていますが、関数への実際のポインターではなく、奇妙なポインターを取得し続けています。(相対的なオフセットを取得しているか、NASMが一時的な値をそこに埋め込んでおり、リンク中に実際の値に置き換えられていないと考えています)

私が構築しようとしている現在のインターフェースは、IClassFactory次のようなコードのインターフェースです。

%define S_OK 0x00000000
%define E_NOINTERFACE 0x80004002

section .text

; All of these have very simple shells rather than implementations, but that is just until I can get the vtable worked out

ClassFactory_QueryInterface:
    mov eax, E_NOINTERFACE
    retn 12

ClassFactory_AddRef:
    mov eax, 1
    retn 4

ClassFactory_Release:
    mov eax, 1
    retn 4

ClassFactory_CreateInstance:
    mov eax, E_NOINTERFACE
    retn 16

ClassFactory_LockServer:
    mov eax, S_OK
    retn 8

global ClassFactory_vtable
ClassFactory_vtable dd ClassFactory_QueryInterface, ClassFactory_AddRef, ClassFactory_Release, ClassFactory_CreateInstance, ClassFactory_LockServer

global ClassFactory_object
ClassFactory_object dd ClassFactory_vtable

注:これはすべてのコードではありません。別のファイルにDllGetClassObject、DllMainなどがあります。

しかし、(NASM:を使用して)アセンブルして(nasm -f win32 comobject.asmMS Link:を使用して)リンクlink /dll /subsystem:windows /out:comobject.dll comobject.objし、OllyDbgを使用して実行可能ファイルを調べると、vtableに奇妙な値が表示されます。たとえば、前回のビルドでは、関数の実際のアドレスは次のとおりです。

  • QueryInterface-0x00381012
  • AddRef-0x0038101A
  • リリース-0x00381020
  • CreateInstance-0x00381026
  • LockServer-0x0038102E

しかし、vtableは次の値で出てきました:

  • QueryInterface-0x00F51012
  • AddRef-0x00F5101A
  • リリース-0x00F51020
  • CreateInstance-0x00F51026
  • LockServer-0x00F5102E

これらの値はひどく疑わしいように見えます...ほとんど移転が行われなかったように。また、vtableは0x00F5104Aとして出力され、これらはすべてアクセスできないメモリアドレスです。(情報提供の目的で、これらの値は毎回異なります

Visual Studio 2010Expressを使用してC++で同じことを試してみましたが、すべてうまくいきました。だから私はそれが私のアセンブリに欠けているものだと思います...


これらの値が適切に出力されない理由を誰かが私に指摘できますか?

4

3 に答える 3

2

申し訳ありませんが、問題は私自身のせいであることが判明しました...物事を構築するすべての/dll混乱において、リンカー呼び出しからを削除し、DLLではなくEXEとして構築されました...


これに出くわす次の人のために、これをもう少しよく説明しましょう。

すべてのWindows実行可能ファイルには、実行可能ファイルがロードされる仮想アドレスであると想定されるベースアドレスがあります。実行中のプロセスにロードされる実行可能ファイルは、ほとんどの場合、「優先」ベースアドレスにロードされません。これは、別のDLL(またはアプリケーション自体)がすでにアドレスを占有している可能性があるためです。このため、WindowsPE実行可能ファイルはいわゆる再配置テーブルを使用します。再配置テーブルは、新しいベースアドレスに再配置する場合に、実行可能ファイル内のどの場所を書き換える必要があるかをWindowsに通知します。

ただし、仮想メモリの出現により、実行可能ファイルは常にベースアドレスにロードされるため、ほとんどのリンカは最適化としてEXEから再配置テーブルを省略します(予約されたカーネルアドレスと競合する場合を除きます。競合する場合は失敗します)。一緒にロードします)。そのため、DLLとしてのコンパイルを停止したため、実行可能ファイルに再配置テーブルが与えられず、その結果、実行中のプロセスのアドレス空間に正しく読み込まれませんでした。


アップデート:

デフォルトでは、MSDNで説明されているように、MSVCにはDLLプロジェクトの再配置テーブルのみが含まれます。

By default, /FIXED:NO is the default when building a DLL, and /FIXED is the default for any other project type.

この動作は/FIXED:NO、リンカーにスイッチを提供することで変更できます。非DLLプロジェクトのデフォルトは/FIXED、ターゲットが固定ベースアドレスを持ち、再配置テーブルを必要としないことをリンカに通知するものです。

于 2010-08-02T05:55:38.333 に答える
1

CでスタブCOMインターフェイスを構築し、結果を分解しようとしましたか?これにより、実装で何が問題になっているのかがわかります。

于 2010-07-26T00:42:35.507 に答える
1

グローバルをエクスポートとして宣言しようとしましたか?私は長い間x86を実行していません。しかし、nasmのドキュメントを読むと、DLL再配置修正が機能するためにグローバルとエクスポートの両方が必要であることが示唆されているようです。

于 2010-07-27T11:25:07.530 に答える