标签:lrm lis cux 自动 rgs 默认 创建 tms cti
IL是.NET框架中中间语言(Intermediate Language)的缩写。使用.NET框架提供的编译器可以直接将源程序编译为.exe或.dll文件,但此时编译出来的程序代码并不是CPU能直接执行的机器代码,而是一种中间语言IL(Intermediate Language)的代码(来源百度)
安装VS的时候会安装一款IL查看工具,【ildasm】,位于:C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6 Tools,依据版本不同可能实际路径不一样,但都位于:C:\Program Files (x86)\Microsoft SDKs\Windows目录下
一款开源的C#反编译工具,个人比较喜欢用这个看,因为对于关键字有颜色标记,IL指令还能直接导航到微软网站查看此指令的解释,下载地址:点这里
当然还有老牌的Reflector,不过要注册。。。
这个网上有很多,MSDN上也有说明,我推荐一位博友的帖子 -->>> 点这里
Managed Heap(托管堆):这就是NET中的托管堆,用来存放引用类型,它是由GC(垃圾回收器自动进行回收)管理,每个进程共享此空间;
Call Stack(调用堆栈):每个线程都有自己专属的调用堆栈, 保存运行期间所调用的方法,方法参数,返回地址,以及局部变量,当方法调用完毕后,会丢弃相关信息
Evaluation Stack(计算堆栈):每个线程都有自己的线程栈,IL 里面的任何计算,都发生在 Evaluation Stack 上,其实就是一个 Stack 结构。可以 Push,也可以 Pop。
C#代码:
1 static void Main(string[] args) 2 { 3 int i = 0; 4 int j = i + 5; 5 List<string> list = new List<string>() 6 { 7 "1","2","3","4","5" 8 }; 9 IEnumerator<string> listt = list.GetEnumerator(); 10 while (listt.MoveNext()) 11 { 12 Console.WriteLine(listt.Current); 13 } 14 15 foreach (var item in list) 16 { 17 Console.WriteLine(item); 18 } 19 20 Console.ReadLine(); 21 } 22 }
IL代码:
.class private auto ansi beforefieldinit SomeThingTest.Program extends [mscorlib]System.Object { // 方法 .method private hidebysig static void Main ( string[] args ) cil managed { // 方法起始 RVA 地址 0x2050 // 方法起始地址(相对于文件绝对值:0x0250) // 代码长度 176 (0xb0) .maxstack 3 .entrypoint .locals init ( [0] int32, [1] int32, [2] class [mscorlib]System.Collections.Generic.List`1<string>, [3] class [mscorlib]System.Collections.Generic.IEnumerator`1<string>, [4] bool, [5] valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>, [6] string ) // 0x025C: 00 IL_0000: nop // 0x025D: 16 IL_0001: ldc.i4.0 // 0x025E: 0A IL_0002: stloc.0 // 0x025F: 06 IL_0003: ldloc.0 // 0x0260: 1B IL_0004: ldc.i4.5 // 0x0261: 58 IL_0005: add // 0x0262: 0B IL_0006: stloc.1 // 0x0263: 73 0F 00 00 0A IL_0007: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor() // 0x0268: 25 IL_000c: dup // 0x0269: 72 01 00 00 70 IL_000d: ldstr "1" // 0x026E: 6F 10 00 00 0A IL_0012: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) // 0x0273: 00 IL_0017: nop // 0x0274: 25 IL_0018: dup // 0x0275: 72 05 00 00 70 IL_0019: ldstr "2" // 0x027A: 6F 10 00 00 0A IL_001e: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) // 0x027F: 00 IL_0023: nop // 0x0280: 25 IL_0024: dup // 0x0281: 72 09 00 00 70 IL_0025: ldstr "3" // 0x0286: 6F 10 00 00 0A IL_002a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) // 0x028B: 00 IL_002f: nop // 0x028C: 25 IL_0030: dup // 0x028D: 72 0D 00 00 70 IL_0031: ldstr "4" // 0x0292: 6F 10 00 00 0A IL_0036: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) // 0x0297: 00 IL_003b: nop // 0x0298: 25 IL_003c: dup // 0x0299: 72 11 00 00 70 IL_003d: ldstr "5" // 0x029E: 6F 10 00 00 0A IL_0042: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) // 0x02A3: 00 IL_0047: nop // 0x02A4: 0C IL_0048: stloc.2 // 0x02A5: 08 IL_0049: ldloc.2 // 0x02A6: 6F 11 00 00 0A IL_004a: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator() // 0x02AB: 8C 02 00 00 1B IL_004f: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> // 0x02B0: 0D IL_0054: stloc.3 // 0x02B1: 2B 0E IL_0055: br.s IL_0065 // 循环开始 (head: IL_0065) // 0x02B3: 00 IL_0057: nop // 0x02B4: 09 IL_0058: ldloc.3 // 0x02B5: 6F 12 00 00 0A IL_0059: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current() // 0x02BA: 28 13 00 00 0A IL_005e: call void [mscorlib]System.Console::WriteLine(string) // 0x02BF: 00 IL_0063: nop // 0x02C0: 00 IL_0064: nop // 0x02C1: 09 IL_0065: ldloc.3 // 0x02C2: 6F 14 00 00 0A IL_0066: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() // 0x02C7: 13 04 IL_006b: stloc.s 4 // 0x02C9: 11 04 IL_006d: ldloc.s 4 // 0x02CB: 2D E6 IL_006f: brtrue.s IL_0057 // 循环结束 // 0x02CD: 00 IL_0071: nop // 0x02CE: 08 IL_0072: ldloc.2 // 0x02CF: 6F 11 00 00 0A IL_0073: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator() // 0x02D4: 13 05 IL_0078: stloc.s 5 .try { // 0x02D6: 2B 13 IL_007a: br.s IL_008f // 循环开始 (head: IL_008f) // 0x02D8: 12 05 IL_007c: ldloca.s 5 // 0x02DA: 28 15 00 00 0A IL_007e: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current() // 0x02DF: 13 06 IL_0083: stloc.s 6 // 0x02E1: 00 IL_0085: nop // 0x02E2: 11 06 IL_0086: ldloc.s 6 // 0x02E4: 28 13 00 00 0A IL_0088: call void [mscorlib]System.Console::WriteLine(string) // 0x02E9: 00 IL_008d: nop // 0x02EA: 00 IL_008e: nop // 0x02EB: 12 05 IL_008f: ldloca.s 5 // 0x02ED: 28 16 00 00 0A IL_0091: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext() // 0x02F2: 2D E4 IL_0096: brtrue.s IL_007c // 循环结束 // 0x02F4: DE 0F IL_0098: leave.s IL_00a9 } // .try 结束 finally { // 0x02F6: 12 05 IL_009a: ldloca.s 5 // 0x02F8: FE 16 02 00 00 1B IL_009c: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> // 0x02FE: 6F 17 00 00 0A IL_00a2: callvirt instance void [mscorlib]System.IDisposable::Dispose() // 0x0303: 00 IL_00a7: nop // 0x0304: DC IL_00a8: endfinally } // 捕捉结束 // 0x0305: 28 18 00 00 0A IL_00a9: call string [mscorlib]System.Console::ReadLine() // 0x030A: 26 IL_00ae: pop // 0x030B: 2A IL_00af: ret } // 方法 Program::Main 结束 .method public hidebysig specialname rtspecialname instance void .ctor () cil managed { // 方法起始 RVA 地址 0x211c // 方法起始地址(相对于文件绝对值:0x031c) // 代码长度 8 (0x8) .maxstack 8 // 0x031D: 02 IL_0000: ldarg.0 // 0x031E: 28 19 00 00 0A IL_0001: call instance void [mscorlib]System.Object::.ctor() // 0x0323: 00 IL_0006: nop // 0x0324: 2A IL_0007: ret } // 方法 Program::.ctor 结束 } // 类 SomeThingTest.Program 结束
接下来我会一步一步分析代码,鉴于我也是初学,很多不懂的地方我也不敢乱说,只介绍我了解的,如果不对,谢谢指出。
.class:说明这是一个class,这个很简单一看就懂
.method:说明这是一个方法,也很简单
private,public:访问修饰符,也不多说
hidebysig:相当于 new
.entrypoint:表示程序的入口
.locals init:本方法所使用的变量,只是对Call Stack的一个具体展现,这所使用的变量包含程序中正常声明的,以及运行中需要的 ,例: while (listt.MoveNext()),这个循环需要一个bool变量,在编译的时候这个变量是被声明在Call Stack中的,展现于.locals init。
.maxstack:对于这个我详细讲下,此表示本方法运行时,【同时】需要的最大的栈大小,也就是Evaluation Stack的最大深度。怎么理解这个最大深度?
举个栗子:
1 int a = 1; 2 int b = 2; 3 int c = 3; 4 int d = a + b + c; 5 Console.WriteLine(d);
// 方法 .method public hidebysig instance void test () cil managed { // 方法起始 RVA 地址 0x2144 // 方法起始地址(相对于文件绝对值:0x0344) // 代码长度 21 (0x15) .maxstack 2 .locals init ( [0] int32, [1] int32, [2] int32, [3] int32 ) // 0x0350: 00 IL_0000: nop // 0x0351: 17 IL_0001: ldc.i4.1 // 0x0352: 0A IL_0002: stloc.0 // 0x0353: 18 IL_0003: ldc.i4.2 // 0x0354: 0B IL_0004: stloc.1 // 0x0355: 19 IL_0005: ldc.i4.3 // 0x0356: 0C IL_0006: stloc.2 // 0x0357: 06 IL_0007: ldloc.0 // 0x0358: 07 IL_0008: ldloc.1 // 0x0359: 58 IL_0009: add // 0x035A: 08 IL_000a: ldloc.2 // 0x035B: 58 IL_000b: add // 0x035C: 0D IL_000c: stloc.3 // 0x035D: 09 IL_000d: ldloc.3 // 0x035E: 28 1A 00 00 0A IL_000e: call void [mscorlib]System.Console::WriteLine(int32) // 0x0363: 00 IL_0013: nop // 0x0364: 2A IL_0014: ret } // 方法 testtest::test 结束
IL_0000~IL_0006:此段为声明变量,并加载到Call Stack(调用堆栈)上,过程为:通过指令加载具体的【数值】到Evaluation Stack(计算堆栈),然后弹出并赋值到Call Stack(调用堆栈)
IL_0007: ldloc.0:加载索引为0的局部到堆栈上,换种说法就是说:从Call Stack加载索引为0的变量到Evaluation Stack中,此时栈的深度为【1】
IL_0008: ldloc.1:加载索引为1的局部到堆栈上,此时栈的深度为【2】
IL_0009: add:将两个值相加并将结果推送到计算堆栈上。此步骤我个人是这样理解的:计算完成后会清空加载到栈上的两个值,此时栈的深度为【0】;并将计算出的值放入栈,此时栈的深度为【1】
所以 a + b + c,是两两相加,直到计算完成,所以最大的栈深度为【2】
对于.maxstack,有个方法比较特殊,那就是构造方法,【.maxstack 8】,这点其实我不是很明白,我看过很多都是8,不只是默认的,还是怎么的,如果知道的友友,还请留下你的见解
1 int i = 0; 2 int j = i + 5;
1 // 0x025C: 00 2 IL_0000: nop //无操作 3 // 0x025D: 16 4 IL_0001: ldc.i4.0 //将数值【0】推送到计算堆栈上 5 // 0x025E: 0A 6 IL_0002: stloc.0 //弹出计算堆栈顶部的值并赋值到调用堆栈索引为0的位置(也就是把刚才推送到的0赋值到调用堆栈索引为0的位置) 7 // 0x025F: 06 8 IL_0003: ldloc.0 //从调用堆栈上索引为0位置的值加载到计算堆栈上 9 // 0x0260: 1B 10 IL_0004: ldc.i4.5 //将数值【5】推送到计算堆栈上 11 // 0x0261: 58 12 IL_0005: add //相加,并将结果推送到计算堆栈上 13 // 0x0262: 0B 14 IL_0006: stloc.1 //弹出计算堆栈顶部的值并赋值到调用堆栈索引为1的位置(也就是把刚才相加的结果赋值到调用堆栈索引为1的位置)
1 List<string> list = new List<string>() 2 { 3 "1","2","3","4","5" 4 };
1 // 0x0263: 73 0F 00 00 0A 2 IL_0007: newobj instance void class [mscorlib]System.Collections.Generic.List`1<string>::.ctor() //创建一个类型为List<string>的对象并推送到计算堆栈上,此时栈深度为【1】 3 // 0x0268: 25 4 IL_000c: dup //复制计算堆栈顶部的值,复制引用,并推送到计算堆栈上,此时深度为【2】 5 // 0x0269: 72 01 00 00 70 6 IL_000d: ldstr "1" //加载字符串【1】到计算堆栈上,此时深度为【3】 7 // 0x026E: 6F 10 00 00 0A 8 IL_0012: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) //调用Add方法,完成后清空刚才参与运算的变量,也就是List<string> 对象的副本,与字符串【1】,由于此方法没有返回值,并不会推送任何值到计算堆栈上,此时深度为【1】 9 // 0x0273: 00 10 IL_0017: nop //此位置到IL_0042都是重复此操作 11 // 0x0274: 25 12 IL_0018: dup 13 // 0x0275: 72 05 00 00 70 14 IL_0019: ldstr "2" 15 // 0x027A: 6F 10 00 00 0A 16 IL_001e: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) 17 // 0x027F: 00 18 IL_0023: nop 19 // 0x0280: 25 20 IL_0024: dup 21 // 0x0281: 72 09 00 00 70 22 IL_0025: ldstr "3" 23 // 0x0286: 6F 10 00 00 0A 24 IL_002a: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) 25 // 0x028B: 00 26 IL_002f: nop 27 // 0x028C: 25 28 IL_0030: dup 29 // 0x028D: 72 0D 00 00 70 30 IL_0031: ldstr "4" 31 // 0x0292: 6F 10 00 00 0A 32 IL_0036: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) 33 // 0x0297: 00 34 IL_003b: nop 35 // 0x0298: 25 36 IL_003c: dup 37 // 0x0299: 72 11 00 00 70 38 IL_003d: ldstr "5" 39 // 0x029E: 6F 10 00 00 0A 40 IL_0042: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<string>::Add(!0) 41 // 0x02A3: 00 42 IL_0047: nop //无操作 43 // 0x02A4: 0C 44 IL_0048: stloc.2 //弹出顶部的值并放入调用堆栈索引为【2】的位置,此时深度为【0】
1 IEnumerator<string> listt = list.GetEnumerator(); 2 while (listt.MoveNext()) 3 { 4 Console.WriteLine(listt.Current); 5 }
1 IL_0049: ldloc.2 //加载调用堆栈索引为2的值到计算堆栈上,此时深度为【1】 2 // 0x02A6: 6F 11 00 00 0A 3 IL_004a: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator() //调用GetEnumerator(),并将返回值推送到计算堆栈上,注意【GetEnumerator(),返回的是Enumerator类型,此类型是个结构,是值类型,明白这一点才清楚下一步】,此时深度为【1】 4 // 0x02AB: 8C 02 00 00 1B 5 IL_004f: box valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> //进行装箱,转换成object类型,因为上一步返回的是值类型,所以在这一步进行装箱,过程:弹出上一步返回的值,进行装箱,并将对象的引用推送到计算堆栈上,此时深度为【1】 6 // 0x02B0: 0D 7 IL_0054: stloc.3 //弹出顶部的值,并放入调用堆栈索引为3的位置 此时深度为【0】 8 // 0x02B1: 2B 0E 9 IL_0055: br.s IL_0065 // 直接跳转到 IL_0065处,开始循环 10 // 循环开始 (head: IL_0065) 11 // 0x02B3: 00 12 IL_0057: nop //无操作 13 // 0x02B4: 09 14 IL_0058: ldloc.3 //加载调用堆栈中索引为3的值推送到计算堆栈,此时深度为【1】 15 // 0x02B5: 6F 12 00 00 0A 16 IL_0059: callvirt instance !0 class [mscorlib]System.Collections.Generic.IEnumerator`1<string>::get_Current() //调用get_Current(),将返回值推送到计算堆栈上,此时深度为【1】 17 // 0x02BA: 28 13 00 00 0A 18 IL_005e: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine方法,此时深度为【0】 19 // 0x02BF: 00 20 IL_0063: nop //无操作 21 // 0x02C0: 00 22 IL_0064: nop //无操作 23 24 // 0x02C1: 09 25 IL_0065: ldloc.3 //加载调用堆栈中索引为3的值推送到计算堆栈,此时深度为【1】 26 // 0x02C2: 6F 14 00 00 0A 27 IL_0066: callvirt instance bool [mscorlib]System.Collections.IEnumerator::MoveNext() //调用MoveNext(),返回的bool 推送到计算堆栈上 ,此时深度为【1】 28 // 0x02C7: 13 04 29 IL_006b: stloc.s 4 // 弹出顶的值,放入调用堆栈索引为4的位置,此时深度为【0】 30 // 0x02C9: 11 04 31 IL_006d: ldloc.s 4 //加载调用堆栈中索引为4的值推送到计算堆栈,此时深度为【1】 32 // 0x02CB: 2D E6 33 IL_006f: brtrue.s IL_0057 //如果为 true、非空或非零,则跳转到IL_0057的位置,此时深度为【0】 34 // 循环结束
1 foreach (var item in list) 2 { 3 Console.WriteLine(item); 4 } 5 6 Console.ReadLine();
1 // 0x02CD: 00 2 IL_0071: nop //无操作 3 // 0x02CE: 08 4 IL_0072: ldloc.2 //加载调用堆栈中索引为2的值推送到计算堆栈,此时深度为【1】 5 // 0x02CF: 6F 11 00 00 0A 6 IL_0073: callvirt instance valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<!0> class [mscorlib]System.Collections.Generic.List`1<string>::GetEnumerator()//调用GetEnumerator() ,因为foreach的对象本身就是一个可迭代的对象,所以是使用迭代器,返回值同样是一个值类型,但是没有变量接收,所以不需要装箱,此时深度为【1】 7 // 0x02D4: 13 05 8 IL_0078: stloc.s 5 //弹出顶部的值,放入调用堆栈索引为5的位置,此时深度为【0】 9 .try 10 { 11 // 0x02D6: 2B 13 12 IL_007a: br.s IL_008f //跳转到IL_008f 13 // 循环开始 (head: IL_008f) 14 // 0x02D8: 12 05 15 IL_007c: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】 16 // 0x02DA: 28 15 00 00 0A 17 IL_007e: call instance !0 valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::get_Current() //调用get_Current() 获取当前迭代器当前位置的值 ,此时深度为【1】 18 // 0x02DF: 13 06 19 IL_0083: stloc.s 6 // 弹出顶的值,放入调用堆栈索引为6的位置,此时深度为【0】 20 // 0x02E1: 00 21 IL_0085: nop //无操作 22 // 0x02E2: 11 06 23 IL_0086: ldloc.s 6 //加载调用堆栈中索引为6的值推送到计算堆栈,此时深度为【1】 24 // 0x02E4: 28 13 00 00 0A 25 IL_0088: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine方法,此时深度为【0】 26 // 0x02E9: 00 27 IL_008d: nop //无操作 28 // 0x02EA: 00 29 IL_008e: nop //无操作 30 31 // 0x02EB: 12 05 32 IL_008f: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】 33 // 0x02ED: 28 16 00 00 0A 34 IL_0091: call instance bool valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string>::MoveNext() //调用MoveNext() 返回值为bool ,此时深度为【1】 35 // 0x02F2: 2D E4 36 IL_0096: brtrue.s IL_007c //如果为 true、非空或非零,则跳转到IL_007c的位置,此时深度为【0】 37 // 循环结束 38 39 // 0x02F4: DE 0F 40 IL_0098: leave.s IL_00a9 //退出受保护的代码区域,跳转到IL_00a9 41 } // .try 结束 42 finally 43 { 44 // 0x02F6: 12 05 45 IL_009a: ldloca.s 5 //加载调用堆栈中索引为5的值推送到计算堆栈,此时深度为【1】 ,说明下:这个值是循环是的迭代器对象 46 // 0x02F8: FE 16 02 00 00 1B 47 IL_009c: constrained. valuetype [mscorlib]System.Collections.Generic.List`1/Enumerator<string> //约束要对其进行虚方法调用的类型。 这里的话,清楚Call与Callvirt区别就知道为啥要这样了。。。我不是很了解这个,不敢乱说,望知道的友友留下你的见解,关于【constrained】指令的解释: https://msdn.microsoft.com/library/system.reflection.emit.opcodes.constrained.aspx 48 // 0x02FE: 6F 17 00 00 0A 49 IL_00a2: callvirt instance void [mscorlib]System.IDisposable::Dispose() //调用Dispose(),释放迭代器,此时深度为【0】 50 // 0x0303: 00 51 IL_00a7: nop //无操作 52 // 0x0304: DC 53 IL_00a8: endfinally //结束捕获 54 } // 捕捉结束 55 // 0x0305: 28 18 00 00 0A 56 IL_00a9: call string [mscorlib]System.Console::ReadLine() //调用ReadLine(),此时深度为【1】 57 // 0x030A: 26 58 IL_00ae: pop //移除当前位于计算堆栈顶部的值。 对于这个我是这样理解的:ReadLine() 会返回要给string类型的值,但是没有变量接收,所以会移除这个值 59 // 0x030B: 2A 60 IL_00af: ret //从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。
以上都是本人的个人理解,如果不对,谢谢指出!
分享个我当时遇到过的题目:
List<string> _List = new List<string>(); public string this[int i] { get { return _List[i]; } } public string get_Item(int i) { return _List[i]; }
问:这段代码有错么,如果有错在哪呢?
标签:lrm lis cux 自动 rgs 默认 创建 tms cti
原文地址:http://www.cnblogs.com/FreeEasy/p/7744121.html