当前位置: 动力学知识库 > 问答 > 编程问答 >

c# - Same method has different entry address in native code?

问题描述:

I've written the following C# in .NET 4.5:

public struct DisposableStruct : IDisposable {

private readonly int _i, _j;

public DisposableStruct(int i, int j) {

_i = i;

_j = j;

}

[MethodImpl(MethodImplOptions.NoInlining)]

void IDisposable.Dispose() {

Console.WriteLine(_i + _j);

}

}

internal class Program {

[MethodImpl(MethodImplOptions.AggressiveInlining)]

private static void Dispose<T>(ref T obj) where T : IDisposab

obj.Dispose();

}

[MethodImpl(MethodImplOptions.AggressiveInlining)]

private static void Dispose<T>(T obj) where T : IDisposable {

obj.Dispose();

}

[MethodImpl(MethodImplOptions.NoInlining)]

private static void Test() {

var ds = new DisposableStruct(1, 2);

Dispose(ref ds);

}

[MethodImpl(MethodImplOptions.NoInlining)]

private static void TestNoRef() {

var ds = new DisposableStruct(1, 2);

Dispose(ds);

}

private static unsafe void Main() {

Test();

TestNoRef();

Console.WriteLine(Process.GetCurrentProcess().Id);

Console.ReadLine();

}

}

I'm dump the memory after the pause with the printed the process id, but found something strange. Here's the native code of Test:

0:000> !u 000007fd85c30120

Normal JIT generated code

SimpleConsole.Program.Test()

Begin 000007fd85c30120, size 40

*** WARNING: Unable to verify checksum for SimpleConsole.exe

c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 40:

>>> 000007fd`85c30120 4883ec38 sub rsp,38h

000007fd`85c30124 48c744242800000000 mov qword ptr [rsp+28h],0

000007fd`85c3012d 48c744242000000000 mov qword ptr [rsp+20h],0

000007fd`85c30136 488d442420 lea rax,[rsp+20h]

000007fd`85c3013b 488d4c2428 lea rcx,[rsp+28h]

000007fd`85c30140 c70001000000 mov dword ptr [rax],1

000007fd`85c30146 c7400402000000 mov dword ptr [rax+4],2

000007fd`85c3014d 488b442420 mov rax,qword ptr [rsp+20h]

000007fd`85c30152 488901 mov qword ptr [rcx],rax

000007fd`85c30155 e83ebfeeff call 000007fd`85b1c098 (SimpleConsole.DisposableStruct.System.IDisposable.Dispose(), mdToken: 0000000006000017)

000007fd`85c3015a 90 nop

000007fd`85c3015b 4883c438 add rsp,38h

000007fd`85c3015f c3 ret

and here's the native code of method TestNoRef:

0:000> !u 000007fd85c301b0

Normal JIT generated code

SimpleConsole.Program.TestNoRef()

Begin 000007fd85c301b0, size 42

c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 46:

>>> 000007fd`85c301b0 4883ec38 sub rsp,38h

000007fd`85c301b4 48c744242800000000 mov qword ptr [rsp+28h],0

000007fd`85c301bd 48c744242000000000 mov qword ptr [rsp+20h],0

000007fd`85c301c6 488d442428 lea rax,[rsp+28h]

000007fd`85c301cb c70001000000 mov dword ptr [rax],1

000007fd`85c301d1 c7400402000000 mov dword ptr [rax+4],2

c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 47:

000007fd`85c301d8 488b442428 mov rax,qword ptr [rsp+28h]

000007fd`85c301dd 4889442420 mov qword ptr [rsp+20h],rax

000007fd`85c301e2 488d4c2420 lea rcx,[rsp+20h]

000007fd`85c301e7 e894ffffff call 000007fd`85c30180 (SimpleConsole.DisposableStruct.System.IDisposable.Dispose(), mdToken: 0000000006000017)

000007fd`85c301ec 90 nop

000007fd`85c301ed 4883c438 add rsp,38h

000007fd`85c301f1 c3 ret

We can easily find that the entry address for the same Dispose is different:

  • Test: 000007fd 85b1c098
  • TestNoRef: 000007fd 85c30180

But only the address for TestNoRef is the right one:

0:000> !u 000007fd`85c30180

Normal JIT generated code

SimpleConsole.DisposableStruct.System.IDisposable.Dispose()

Begin 000007fd85c30180, size 19

c:\projects\SimpleConsole\SimpleConsole\Program.cs @ 22:

>>> 000007fd`85c30180 4883ec28 sub rsp,28h

000007fd`85c30184 488bc1 mov rax,rcx

000007fd`85c30187 8b08 mov ecx,dword ptr [rax]

000007fd`85c30189 8b4004 mov eax,dword ptr [rax+4]

000007fd`85c3018c 03c8 add ecx,eax

000007fd`85c3018e e85d8dda5e call mscorlib_ni+0xce8ef0 (000007fd`e49d8ef0) (System.Console.WriteLine(Int32), mdToken: 000000000600098d)

000007fd`85c30193 90 nop

000007fd`85c30194 4883c428 add rsp,28h

000007fd`85c30198 c3 ret

but what's the one in Test?

0:000> !u 000007fd`85b1c098

Unmanaged code

000007fd`85b1c098 e89360765f call clr+0x2130 (000007fd`e5282130)

000007fd`85b1c09d 5e pop rsi

000007fd`85b1c09e 05009048b1 add eax,0B1489000h

000007fd`85b1c0a3 85fd test ebp,edi

000007fd`85b1c0a5 07 ???

000007fd`85b1c0a6 0000 add byte ptr [rax],al

000007fd`85b1c0a8 0000 add byte ptr [rax],al

000007fd`85b1c0aa 0000 add byte ptr [rax],al

000007fd`85b1c0ac 0000 add byte ptr [rax],al

000007fd`85b1c0ae 0000 add byte ptr [rax],al

The result of program is obviously correct, but how does the native code behave for Test method?

网友答案:

This different address 000007fd 85b1c098 is actually an address of Jit stub code, because method SimpleConsole.DisposableStruct.System.IDisposable.Dispose() was not Jit-compiled before Test. Stub code calls Jit compiler on its first call, and patches itself to call compiled method after compilation.

Some information here: http://codeidol.com/csharp/net-framework/Inside-the-CLR/Just-In-Time-(JIT)-Compilation/

分享给朋友:
您可能感兴趣的文章:
随机阅读: