.Net应用程序编译及执行过程
与传统的Windows应用程序相比,.Net应用程序有很多不同的地方,尤其是在编译与执行期间。
首先来看一下编译过程,传统的Windows应用程序会被编译器直接编译成与特定机器相关的本地应用程序,这类程序则只能在特定操作系统及硬件系统上运行,而.Net应用程序在编译时只会被编译成MSIL(中间代码),在运行期间被即时编译成本地指令,从而可达到跨平台的效果,平台则与上层软件完全隔离。
正如先前所说,执行期间MSIL会被编译成本地代码,这有点像解释性编译语言,但却与解释性编译有很大不同,就在于会重用先前编译的本地代码,在每一次执行代码均会查看是否已经编译过,若没有编译成本地代码,则执行一次编译,若编译过,则重用先前的本地代码。
现在通过示例来看看即时编译过程,
测试代码如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Simple
{
class Program
{
class Calc
{
public int DataA { get; set; }
public int DataB { get; set; }
public int Add()
{
return DataA + DataB;
}
}
static void Main(string[] args)
{
Calc oCalc = new Calc();
oCalc.Add();
}
}
}
现在使用Windbg 运行该程序,并在oCalc.Add();前一行设置断点
WARNING: Whitespace at start of path element
WARNING: Path element is empty
CommandLine: E:\test\Simple\Simple\bin\Debug\Simple.exe
Symbol search path is: ;E:\JustTestProjectE\C3C4项目\软件\pdb;;D:\symbols
Executable search path is:
ModLoad: 00400000 00408000 Simple.exe
ModLoad: 77ec0000 77ffc000 ntdll.dll
ModLoad: 79000000 7904a000 C:\Windows\SYSTEM32\MSCOREE.DLL
ModLoad: 77de0000 77eb4000 C:\Windows\system32\KERNEL32.dll
ModLoad: 0dce0000 0dd2b000 C:\Windows\system32\KERNELBASE.dll
(52c.1388): Break instruction exception - code 80000003 (first chance)
eax=00000000 ebx=00000000 ecx=0012fb0c edx=77f06194 esi=fffffffe edi=00000000
eip=77f5e99e esp=0012fb28 ebp=0012fb54 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!LdrpDoDebuggerBreak+0x2c:
77f5e99e cc int 3
0:000> !mbp Program.cs 24.
The CLR has not yet been initialized in the process.
Breakpoint resolution will be attempted when the CLR is initialized.
0:000> g
ModLoad: 77c60000 77d00000 C:\Windows\system32\ADVAPI32.dll
ModLoad: 6ff50000 6fffc000 C:\Windows\system32\msvcrt.dll
ModLoad: 02b20000 02b39000 C:\Windows\SYSTEM32\sechost.dll
ModLoad: 77bb0000 77c51000 C:\Windows\system32\RPCRT4.dll
ModLoad: 603b0000 60416000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
ModLoad: 6de20000 6de77000 C:\Windows\system32\SHLWAPI.dll
ModLoad: 77b60000 77bae000 C:\Windows\system32\GDI32.dll
ModLoad: 77d10000 77dd9000 C:\Windows\system32\USER32.dll
ModLoad: 402c0000 402ca000 C:\Windows\system32\LPK.dll
ModLoad: 6f8e0000 6f97d000 C:\Windows\system32\USP10.dll
ModLoad: 41840000 4185f000 C:\Windows\system32\IMM32.DLL
ModLoad: 70990000 70a5c000 C:\Windows\system32\MSCTF.dll
ModLoad: 79140000 797af000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\clr.dll
ModLoad: 79060000 7911e000 C:\Windows\system32\MSVCR100_CLR0400.dll
(52c.1388): Unknown exception - code 04242420 (first chance)
ModLoad: 79880000 7a642000 C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\d6e053b4e78f3077025a0c035237d5cc\mscorlib.ni.dll
*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v4.0.30319_32\mscorlib\d6e053b4e78f3077025a0c035237d5cc\mscorlib.ni.dll
ModLoad: 60930000 60940000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\nlssorting.dll
ModLoad: 72540000 7269c000 C:\Windows\system32\ole32.dll
ModLoad: 10000000 1000c000 C:\Windows\system32\CRYPTBASE.dll
*** WARNING: Unable to verify checksum for Simple.exe
ModLoad: 79810000 79870000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\clrjit.dll
Breakpoint: JIT notification received for method Simple.Program.Main(System.String[]) in AppDomain 005f1ab0.
Breakpoint set at Simple.Program.Main(System.String[]) in AppDomain 005f1ab0.
Breakpoint 1 hit
eax=02b4b1f8 ebx=00000000 ecx=02b4b1f8 edx=00629758 esi=00629758 edi=0012f410
eip=003c00a9 esp=0012f3d8 ebp=0012f3e4 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
003c00a9 8b4df8 mov ecx,dword ptr [ebp-8] ss:0023:0012f3dc=02b4b1f8
显示当前调用栈各帧局部变量
0:000> !clrstack -a -n
OS Thread Id: 0x1388 (0)
Child SP IP Call Site
0012f3d8 003c00a9 Simple.Program.Main(System.String[])
PARAMETERS:
args (0x0012f3e0) = 0x02b4b1e8
LOCALS:
0x0012f3dc = 0x02b4b1f8
0012f610 791421bb [GCFrame: 0012f610]
接下来查看类Simple的方法表:
0:000> dd 0x02b4b1f8
02b4b1f8 003538d0 00000000 00000000 00000000
02b4b208 00000000 00000000 00000000 00000000
02b4b218 00000000 00000000 00000000 00000000
02b4b228 00000000 00000000 00000000 00000000
02b4b238 00000000 00000000 00000000 00000000
02b4b248 00000000 00000000 00000000 00000000
02b4b258 00000000 00000000 00000000 00000000
02b4b268 00000000 00000000 00000000 00000000
0:000> !dumpmt -md 003538d0
EEClass: 00351494
Module: 00352ea4
Name: Simple.Program+Calc
mdToken: 02000003
File: E:\test\Simple\Simple\bin\Debug\Simple.exe
BaseSize: 0x10
ComponentSize: 0x0
Slots in VTable: 10
Number of IFaces in IFaceMap: 0
--------------------------------------
MethodDesc Table
Entry MethodDesc JIT Name
79aaa790 79884cd8 PreJIT System.Object.ToString()
79aae290 79884ce0 PreJIT System.Object.Equals(System.Object)
79aae1a0 79884d00 PreJIT System.Object.GetHashCode()
79b317b0 79884d14 PreJIT System.Object.Finalize()
003c00d0 003538c8 JIT Simple.Program+Calc..ctor()
0035c03d 0035388c NONE Simple.Program+Calc.get_DataA()
0035c041 00353898 NONE Simple.Program+Calc.set_DataA(Int32)
0035c045 003538a4 NONE Simple.Program+Calc.get_DataB()
0035c049 003538b0 NONE Simple.Program+Calc.set_DataB(Int32)
0035c04d 003538bc NONE Simple.Program+Calc.Add()
很明显地看到未调用的函数标置为 NONE,未被编译成本地语言,而被执行过的代码如Simple.Program+Calc..ctor()构造函数已经设置为 JIT,表示已经被编译成本地语言, PerJIT表示为预编译