在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表只适用于虚拟不是吗?这是构造函数编辑:嗯,问题变得更糟,或更好,或其他什么。
我们正在Visual Studio 2008解决方案中的C#项目中开发.NET功能,并通过Visual Studio进行调试和开发。
但是,最后,此代码将加载到由Win32 Delphi应用程序托管的.NET运行时中。
为了便于实现这些功能,我们还可以配置Visual Studio项目/解决方案/调试器,将生成的dll复制到Delphi应用程序的目录中,然后通过Visual Studio调试器执行Delphi应用程序。 / p>
事实证明,如果我在调试器之外运行程序,问题就会消失,但在调试过程中,每次都会出现问题。
不确定是否有帮助,但由于代码不会在6个月左右的时间内用于生产发布,因此我们很快就会为测试版本带来一些压力。
我稍后会深入了解记忆部分,但可能要到周末才能进入记忆部分,然后发布后续记录。
答案 0 :(得分:3)
数据段是编译器通常将全局变量放入导入地址表所在的位置。
00000029 cmp dword ptr [ecx],ecx
0000002b call dword ptr ds:[1889D0DCh]
第一行实际上是一个空检查,如果位于ECX寄存器中的指针无效,最终会引发NullReferenceException
。
callvirt
MSIL指令必须在调用实际方法之前进行空检查。话虽这么说,我们可以安全地假设这两行汇编代码具有以下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]
)?