【问题标题】:Need some help deciphering a line of assembler code, from .NET JITted code需要帮助从 .NET JITted 代码中破译一行汇编代码
【发布时间】:2010-10-21 09:00:44
【问题描述】:

在 C# 构造函数中,最终调用 this(...),实际调用被转换为:

0000003d  call        dword ptr ds:[199B88E8h]

这里的DS寄存器内容是什么?我知道这是数据段,但是这个调用是通过 VMT 表还是类似的?不过我对此表示怀疑,因为this(...) 不会调用虚方法,而只是调用另一个构造函数。

我问是因为该位置的值在某种程度上似乎很糟糕,如果我按 F11,跟踪到 (Visual Studio 2008),在该调用指令上,程序会因访问冲突而崩溃。

代码位于第 3 方控件库的深处,虽然我有源代码,但我没有使用足够的调试信息编译程序集,我只能通过反汇编程序通过 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 仅用于虚拟不是吗?这是构造函数
  • 构造函数是否还没有被 JITted,这可能意味着调用实际上会通过 JIT shim 调用?恐怕我在这深水区,所以任何事情都可能而且可能会有所帮助。

编辑:嗯,问题只是变得更糟,或者更好,或者其他什么。

我们正在 Visual Studio 2008 解决方案中的 C# 项目中开发 .NET 功能,并通过 Visual Studio 进行调试和开发。

但是,最终,此代码将被加载到由 Win32 Delphi 应用程序托管的 .NET 运行时中。

为了方便对这些功能进行实验,我们还可以配置Visual Studio项目/解决方案/调试器,将生成的dll复制到Delphi应用程序的目录,然后通过Visual Studio调试器执行Delphi应用程序。

事实证明,如果我在调试器之外运行程序,问题就会消失,但在调试期间,它每次都会突然出现。

不确定这是否有帮助,但由于代码不会在另外 6 个月左右的时间内用于生产发布,因此我们很快就会为测试发布减轻一些压力。

我稍后会深入研究记忆部分,但可能要等到周末,然后再发布后续内容。

【问题讨论】:

  • 你能找出ds:[199B88E8h]实际指向的地址并反汇编吗?
  • 这是一个存储在那个地方的地址,并且该地址指向未映射的内存,因此访问冲突。

标签: c# assembly jit access-violation


【解决方案1】:

数据段是编译器通常放置全局变量的地方,也是导入地址表所在的地方。

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]) 的内容?

【讨论】:

  • 是的,明天我会发布我从各种呼叫说明中看到的值。可以说它看起来很奇怪,与所有其他人相比(我停止了导致这一点的每个呼叫指令)。有故障的是唯一一个第一位非零的数字。
猜你喜欢
  • 2014-07-10
  • 2013-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-10
  • 2015-08-26
相关资源
最近更新 更多