4

への呼び出しで終了する C# コンストラクターではthis(...)、実際の呼び出しは次のように変換されます。

0000003d  call        dword ptr ds:[199B88E8h]

ここでの DS レジスタの内容は何ですか? データ セグメントであることはわかっていますが、この呼び出しは VMT テーブルなどを介したものですか? this(...)ただし、仮想メソッドへの呼び出しではなく、単なる別のコンストラクターであるため、それは疑わしいです。

F11 キーを押して (Visual Studio 2008) にトレースすると、その呼び出し命令で、プログラムがアクセス違反でクラッシュします。

コードはサード パーティのコントロール ライブラリの奥深くにあります。ソース コードはありますが、C# コードを介してトレースできる十分なデバッグ情報を使用してコンパイルされたアセンブリがなく、逆アセンブラーのみを使用して、それを実際のコードに合わせます。

問題の C# コードは次のとおりです。

public AxisRangeData(AxisRange range) : this(range, range.Axis) {
}

Reflector には、次の IL コードが表示されます。

.maxstack 8
L_0000: ldarg.0 
L_0001: ldarg.1 
L_0002: ldarg.1 
L_0003: callvirt instance class DevExpress.XtraCharts.AxisBase DevExpress.XtraCharts.AxisRange::get_Axis()
L_0008: call instance void DevExpress.XtraCharts.Native.AxisRangeData::.ctor(class DevExpress.XtraCharts.ChartElement, class DevExpress.XtraCharts.AxisBase)
L_000d: ret 

失敗するのは、同じクラスの他のコンストラクターへの最後の呼び出しです。デバッガーが他のメソッド内に現れることはなく、クラッシュするだけです。

JITting 後のメソッドの逆アセンブリは次のとおりです。

00000000  push        ebp  
00000001  mov         ebp,esp 
00000003  sub         esp,14h 
00000006  mov         dword ptr [ebp-4],ecx 
00000009  mov         dword ptr [ebp-8],edx 
0000000c  cmp         dword ptr ds:[18890E24h],0 
00000013  je          0000001A 
00000015  call        61843511 
0000001a  mov         eax,dword ptr [ebp-4] 
0000001d  mov         dword ptr [ebp-0Ch],eax 
00000020  mov         eax,dword ptr [ebp-8] 
00000023  mov         dword ptr [ebp-10h],eax 
00000026  mov         ecx,dword ptr [ebp-8] 
00000029  cmp         dword ptr [ecx],ecx 
0000002b  call        dword ptr ds:[1889D0DCh]   // range.Axis
00000031  mov         dword ptr [ebp-14h],eax 
00000034  push        dword ptr [ebp-14h] 
00000037  mov         edx,dword ptr [ebp-10h] 
0000003a  mov         ecx,dword ptr [ebp-0Ch] 
0000003d  call        dword ptr ds:[199B88E8h]   // this(range, range.Axis)?
00000043  nop              
00000044  mov         esp,ebp 
00000046  pop         ebp  
00000047  ret              

基本的に私が求めているのはこれです:

  • ds:[ADDR]ここでの間接化の目的は何ですか? VMT-tableは仮想専用ですよね?そしてこれはコンストラクタです
  • コンストラクターはまだ JIT されていない可能性があります。これは、呼び出しが実際に JIT shim を介して呼び出されることを意味する可能性がありますか? 私はここで深海にいるのではないかと心配しているので、何でも役立つかもしれません.

編集:まあ、問題は悪化したか、改善したか、または何でも。

Visual Studio 2008 ソリューションの C# プロジェクトで .NET 機能を開発し、Visual Studio を使用してデバッグと開発を行っています。

ただし、最終的に、このコードは Win32 Delphi アプリケーションによってホストされる .NET ランタイムにロードされます。

このような機能を簡単に実験できるようにするために、Visual Studio プロジェクト/ソリューション/デバッガーを構成して、生成された dll を Delphi アプリのディレクトリにコピーし、Visual Studio デバッガーを介して Delphi アプリを実行することもできます。

デバッガーの外でプログラムを実行すると問題は解決しますが、デバッグ中に毎回問題が発生します。

それが役立つかどうかはわかりませんが、コードの本番リリースはあと 6 か月ほど予定されていないため、間もなく行われるテスト リリースに対するプレッシャーが軽減されます。

後でメモリの部分に飛び込みますが、おそらく週末になるまでは続かないので、フォローアップを投稿します.

4

1 に答える 1

3

データセグメントは、コンパイラが通常グローバル変数を配置する場所であり、インポートアドレステーブルが存在する場所です。

00000029  cmp         dword ptr [ecx],ecx 
0000002b  call        dword ptr ds:[1889D0DCh]

最初の行は実際にはヌルチェックでありNullReferenceException、ECXレジスタにあるポインタが無効な場合は最終的にaを発生させます。

MSIL命令はcallvirt、実際のメソッドを呼び出す前にnullチェックを実行する必要があります。そうは言っても、これらの2行のアセンブリコードには次のMSILコード表現があると安全に想定できます。

class DevExpress.XtraCharts.AxisBase DevExpress.XtraCharts.AxisRange::get_Axis()

そしてコメントされたアセンブリコード:

00000026  mov         ecx,dword ptr [ebp-8]      // store the pointer to the 'range' in ECX
00000029  cmp         dword ptr [ecx],ecx        // null-check
0000002b  call        dword ptr ds:[1889D0DCh]   // range.get_Axis()
00000031  mov         dword ptr [ebp-14h],eax    // store the result in a local variable
00000034  push        dword ptr [ebp-14h]        // push the result onto a stack
00000037  mov         edx,dword ptr [ebp-10h]    // this variable was previously loaded with the 'range' pointer
0000003a  mov         ecx,dword ptr [ebp-0Ch]    // here seems to be stored the actual 'this' pointer
0000003d  call        dword ptr ds:[199B88E8h]   // call the this(...) ctor

なぜクラッシュするのかわかりませんが、メモリ位置(DS:[199B88E8h])の内容を調べてみましたか?

于 2009-04-23T14:31:49.830 に答える