详解.net中IL语言

什么是IL语言

中间语言,又称(IL语言)。充当Clr与.net 平台的中间语言,比如用C#编写程序,编译器首先是把C#代码转译成IL语言,最终由Clr解释执行,下面我们学习下IL语言。

如何读懂IL语言

  • 写一个helloworld的.net 程序,编译运行完成。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    		static void Main(string[] args)
    {
    Console.WriteLine("hello world");
    }
    ```

    - 使用ildasm.exe(C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6 Tools)反编译代码,得到IL代码如下:

    ```IL
    .method private hidebysig static void Main(string[] args) cil managed
    {
    .entrypoint
    // 代码大小 13 (0xd)
    .maxstack 8
    IL_0000: nop
    IL_0001: ldstr "hello world"
    IL_0006: call void [mscorlib]System.Console::WriteLine(string)
    IL_000b: nop
    IL_000c: ret
    } // end of method Program::Main
    ```

    - 查找对应的[指令表](http://blog.csdn.net/xiaouncle/article/details/71248830),来确定对应的含义


    <table class="table">
    <thead>
    <tr>
    <th>指令名称</th>
    <th>说明</th>
    </tr>
    </thead>
    <tbody>
    <tr>
    <td>Ldstr</td>
    <td>推送对元数据中存储的字符串的新对象引用。</td>
    </tr>
    <tr>
    <td>Nop</td>
    <td>如果修补操作码,则填充空间。尽管可能消耗处理周期,但未执行任何有意义的操作。</td>
    </tr>
    <tr>
    <td>Call</td>
    <td>调用由传递的方法说明符指示的方法。</td>
    </tr>
    <tr>
    <td>Ret</td>
    <td>从当前方法返回,并将返回值(如果存在)从调用方的计算堆栈推送到被调用方的计算堆栈上。</td>
    </tr>
    </tbody>
    </table>

    - 其它几个名词的的解释

    **hidebysig**: 与之对就的是hidebyname,这个是确定使用方法的签名还是使用方法的名称来确定调用哪个方法.


    - 整个的IL语言解释

    ```IL
    .method private hidebysig static void Main(string[] args) cil managed
    {
    .entrypoint //代码入口
    // 代码大小 13 (0xd)
    .maxstack 8 //整个程序的堆栈大小
    IL_0000: nop //无实在意义
    IL_0001: ldstr "hello world" //定义字符
    IL_0006: call void [mscorlib]System.Console::WriteLine(string) //调用WriteLine变量
    IL_000b: nop
    IL_000c: ret //返回
    } // end of method Program::Main
    ```


    ### 更复杂的Demo

    - 添加编写如下C#代码:

    ``` C#
    class Program
    {
    static void Main(string[] args)
    {
    var a = 0;
    var b = 1;
    var c = Add(a, b);
    Console.WriteLine(c.ToString());
    }

    public static int Add(int x,int y)
    {
    return x + y;
    }
    }

    ```

    - 生成相关的IL代码及解释

    ``` IL
    .method private hidebysig static void Main(string[] args) cil managed
    {
    .entrypoint
    // 代码大小 27 (0x1b)
    .maxstack 2
    .locals init ([0] int32 a,
    [1] int32 b,
    [2] int32 c) //定义3个变量
    IL_0000: nop
    IL_0001: ldc.i4.0 //将整数值 0 作为 int32 推送到计算堆栈上。
    IL_0002: stloc.0 //从计算堆栈的顶部弹出当前值并将其存储到索引 0 处的局部变量列表中。
    IL_0003: ldc.i4.1 //将整数值 1 作为 int32 推送到计算堆栈上。
    IL_0004: stloc.1 //从计算堆栈的顶部弹出当前值并将其存储到索引 1 处的局部变量列表中。
    IL_0005: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上,这里指a。
    IL_0006: ldloc.1 //将索引 1 处的局部变量加载到计算堆栈上,这里指b。
    IL_0007: call int32 ILTest.Program::Add(int32,
    int32) //调用Add方法
    IL_000c: stloc.2 //将索引 2 处的局部变量加载到计算堆栈上,这里指c。
    IL_000d: ldloca.s c //将位于特定索引处的局部变量的地址加载到计算堆栈上(短格式)。
    IL_000f: call instance string [mscorlib]System.Int32::ToString()
    IL_0014: call void [mscorlib]System.Console::WriteLine(string)
    IL_0019: nop
    IL_001a: ret
    } // end of method Program::Main

    ```

    Add方法:

    ``` IL
    .method public hidebysig static int32 Add(int32 x,int32 y) cil managed
    {
    // 代码大小 9 (0x9)
    .maxstack 2
    .locals init ([0] int32 V_0) //创建一个V_0的局部变量
    IL_0000: nop
    IL_0001: ldarg.0 //将索引为 0 的参数加载到计算堆栈上。
    IL_0002: ldarg.1 //将索引为 1 的参数加载到计算堆栈上。
    IL_0003: add //将两个值相加并将结果推送到计算堆栈上。
    IL_0004: stloc.0
    IL_0005: br.s IL_0007 //无条件地将控制转移到目标指令(短格式)
    IL_0007: ldloc.0 //将索引 0 处的局部变量加载到计算堆栈上。
    IL_0008: ret
    } // end of method Program::Add