IL代码的分析

C#代码html

    class Program
    {
        static void Main(string[] args)
        {
            string b = GetAge();

            Console.ReadKey();
        }

        private static string GetAge()
        {
            var a = "a";
            var b = "a";
            var c = a;
            return c;
        }
    }




使用Reflector 反编译 IL代码app

.class private auto ansi beforefieldinit Program
    extends [mscorlib]System.Object
{
    .method public hidebysig specialname rtspecialname instance void .ctor() cil managed
    {
        .maxstack 8
        L_0000: ldarg.0 
        L_0001: call instance void [mscorlib]System.Object::.ctor()
        L_0006: ret 
    }

    .method private hidebysig static string GetAge() cil managed
    {
        .maxstack 1
        .locals init (
            [0] string str,
            [1] string str2,
            [2] string str3,
            [3] string str4)
        L_0000: nop 
        L_0001: ldstr "a"
        L_0006: stloc.0 
        L_0007: ldstr "a"
        L_000c: stloc.1 
        L_000d: ldloc.0 
        L_000e: stloc.2 
        L_000f: ldloc.2 
        L_0010: stloc.3 
        L_0011: br.s L_0013
        L_0013: ldloc.3 
        L_0014: ret 
    }

    .method private hidebysig static void Main(string[] args) cil managed
    {
        .entrypoint
        .maxstack 1
        .locals init (
            [0] string str)
        L_0000: nop 
        L_0001: call string ILSample.Program::GetAge()
        L_0006: stloc.0 
        L_0007: call valuetype [mscorlib]System.ConsoleKeyInfo [mscorlib]System.Console::ReadKey()
        L_000c: pop 
        L_000d: ret 
    }

}



关键字解释ide

1.  .class中 auto 关键字什么意思?函数

StructLayout特性》《.net托管环境下struct实例字段的内存布局(Layout)和大小(Size)布局



2.  .class中 beforefieldinit 关键字什么意思?
post

这个关键字表示让运行时决定何时调用静态构造函数,也可能在调用函数的开始处,也可能偏偏在第一次访问静态成员或者第一次实例化以前。spa

总之是运行时决定的,只要在你用到这个类以前搞定就行了.net

若是没有这个关键字,则运行时偏偏在第一次访问静态成员或者第一次实例化以前调用静态构造函数。code

至于C#编译的IL什么状况下有这个关键字何时没有关键字,判断起来也很容易,若是有显式的静态构造函数,就没有这个关键字,若是没有显式的构造函数,就有这个关键字。
orm


关于beforefieldinit还有不少有意思的内容,能够参考下面这些园子里高手的文章

关于Type Initializer和 BeforeFieldInit的问题,看看你们可否给出正确的解释

[你必须知道的.NET]第二十三回:品味细节,深刻.NET的类型构造器

对beforefieldinit的理解

静态构造函数的执行时机



3.  .method中 .entrypoint 关键字什么意思?

.entrypoint这个比较简单,就是程序的入口点,若是是.EXE的程序集有且只能有一个,若是是.DLL的程序集,固然能够没有入口点。

C#的Main()函数,就被编译器加上了.entrypoint,IL编译器是不认Main()的,只认.entrypoint,因此在IL中,你能够随便让一个函数看成入口。不必非是Main()。


4.  .method中 hidebysig 关键字什么意思?

 基本至关于C#中的new关键字


5.  每一个指令前边的 IL_00XX: 是神马东西

IL_XXXX:其实就是语句的标号,这里的这些标号是ILDASM生成的,就程序执行来讲并无意义。

咱们也能够根据本身的状况来写标号,好比"BEGIN: END:"等等

也能够经过标号让程序来跳转,C#不也是有这个功能的么?

接下来的问题就是IL_XXXX后便XXXX这几个数字了,是按什么编号的?其实很明显感受是相对于方法入口的地址偏移。

为了证明这一点,我也没想到什么好办法,随便写了一个C#程序,反编译后为

复制代码
IL_0000:  ldstr      "dddddddddddddddd" //72 
IL_0005: call void [mscorlib]System.Console::WriteLine(string) //28
IL_000a: ldstr "ffffffffffffffff" //72
IL_000f: call void [mscorlib]System.Console::WriteLine(string) //28
IL_0014: ldstr "dddddddddddddddd" //72
IL_0019: call void [mscorlib]System.Console::WriteLine(string) //28
IL_001e: ldc.i4.3 //19
IL_001f: stloc.0 //0A
IL_0020: ldc.i4.4 //1A
IL_0021: stloc.1 //0B
IL_0022: ldloc.0 //06
IL_0023: ldloc.1 //07
IL_0024: add //58
IL_0025: stloc.2 //0C
IL_0026: ldloc.2 //08
IL_0027: call void [mscorlib]System.Console::WriteLine(int32) //28
IL_002c: ret //2A
复制代码

用UltraEdit打开了.EXE文件。

找到这段IL代码表示二进制代码(OpCode),查找的方法固然要找到每条指令对应的OpCode,

好比0x72表明ldstr;0x28表明call;0x19表明ldc.i4.3  更多须要参考《MSIL指令\操做\Opcode对照表

按照内存的顺序将列下来,就很容易看出来代码地址偏移的关系。

相关文章
相关标签/搜索