详解.net中IL语言

老付     2017-10-08   3243   9min  

什么是IL语言

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

如何读懂IL语言

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

          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代码如下:

          .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
    
  • 查找对应的指令表,来确定对应的含义

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

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

  • 整个的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#代码:

      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代码及解释

	.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方法:

	.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
(本文完)

作者:付威

如果觉得对您有帮助,可以下方的订阅,或者选择右侧捐赠作者,如果有问题,请在捐赠后咨询,谢谢合作

如有任何知识产权、版权问题或理论错误,还请指正。

自由转载-非商用-非衍生-保持署名,请遵循:创意共享3.0许可证

交流请加群113249828: 点击加群   或发我邮件 laofu_online@163.com