Need some help deciphering a line of assembler code, from .NET JITted code
Posted
by Lasse V. Karlsen
on Stack Overflow
See other posts from Stack Overflow
or by Lasse V. Karlsen
Published on 2009-04-23T13:53:49Z
Indexed on
2010/04/15
21:43 UTC
Read the original article
Hit count: 351
In a C# constructor, that ends up with a call to this(...)
, the actual call gets translated to this:
0000003d call dword ptr ds:[199B88E8h]
What is the DS register contents here? I know it's the data-segment, but is this call through a VMT-table or similar? I doubt it though, since this(...)
wouldn't be a call to a virtual method, just another constructor.
I ask because the value at that location seems to be bad in some way, if I hit F11, trace into (Visual Studio 2008), on that call-instruction, the program crashes with an access violation.
The code is deep inside a 3rd party control library, where, though I have the source code, I don't have the assemblies compiled with enough debug information that I can trace it through C# code, only through the disassembler, and then I have to match that back to the actual code.
The C# code in question is this:
public AxisRangeData(AxisRange range) : this(range, range.Axis) {
}
Reflector shows me this IL code:
.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
It's that last call there, to the other constructor of the same class, that fails. The debugger never surfaces inside the other method, it just crashes.
The disassembly for the method after JITting is this:
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
Basically what I'm asking is this:
- What the purpose of the
ds:[ADDR]
indirection here? VMT-table is only for virtual isn't it? and this is constructor - Could the constructor have yet to be JITted, which could mean that the call would actually call through a JIT shim? I'm afraid I'm in deep water here, so anything might and could help.
Edit: Well, the problem just got worse, or better, or whatever.
We are developing the .NET feature in a C# project in a Visual Studio 2008 solution, and debugging and developing through Visual Studio.
However, in the end, this code will be loaded into a .NET runtime hosted by a Win32 Delphi application.
In order to facilitate easy experimentation of such features, we can also configure the Visual Studio project/solution/debugger to copy the produced dll's to the Delphi app's directory, and then execute the Delphi app, through the Visual Studio debugger.
Turns out, the problem goes away if I run the program outside of the debugger, but during debugging, it crops up, every time.
Not sure that helps, but since the code isn't slated for production release for another 6 months or so, then it takes some of the pressure off of it for the test release that we have soon.
I'll dive into the memory parts later, but probably not until over the weekend, and post a followup.
© Stack Overflow or respective owner