公共基礎(chǔ)-IL入門與提高

入門

IL是什么?

IL(Intermediate Language),它也稱為CIL或者M(jìn)SIL,中文就是“中間語言”。IL由ECMA組織(ECMA-335標(biāo)準(zhǔn))提供完整的定義和規(guī)范。我們可以直接把C#源碼編譯為.exe或dll文件,但是此時(shí)編譯出來的程序代碼并不是CPU能直接執(zhí)行的二進(jìn)制代碼,而是IL代碼。

IL分析工具,如何使用?

工具

  1. ILDasm.exe
# 尋找路徑
+ C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX x.x Tools
# 官方文檔
+ https://docs.microsoft.com/en-us/dotnet/framework/tools/ildasm-exe-il-disassembler

ILDasm.exe說明

1. 可視化分析
  1. 編寫常見的HelloWorld,沒有復(fù)雜的代碼。
using System;

namespace ILLearning
{
    class Program
    {
        static void Main(string[] args)
        {
            string helloString = "Hello World";
            Console.WriteLine(helloString);
            Console.ReadLine();
        }
    }
}
  1. 使用csc.exe編譯,具體可以參考:C#命令行編譯器的步驟介紹

  2. 運(yùn)行ILDasm.exe,拖剛剛編譯的exe進(jìn)來,界面如下:

    參考ILDasm_MainForm.png

從上圖可以看到IL結(jié)構(gòu):包含MANIFEST文件和ILLearning,其中MANIFEST是一個(gè)清單文件,主要包括程序集的一些屬性,例如程序集名稱、版本號(hào)、哈希算法、程序集模塊,以及對(duì)外部引用程序的引用項(xiàng)目。.Program類是我們要主要介紹的內(nèi)容。

2. 命令行操作
  1. 常見命令

    > ildasm MyFile.exe /output:MyFile.il
    

IL指令

  • 中文參考

  • MSDN Ref

    • Emit實(shí)踐

      using System;
      using System.Reflection;
      using System.Reflection.Emit;
      
      namespace ILLearning
      {
          class EmitTest
          {
              static void Main(string[] args)
              {
                  #region Emit練習(xí)
                  // specify a new assembly name 
                  var assemblyName = new AssemblyName("World");
                  // create assemblybuilder
                  /*
                  * AssemblyBuilderAccess枚舉值說明:
                  * AssemblyBuilderAccess.Run; 表示程序集可被執(zhí)行,但不能被保存?! ?            * AssemblyBuilderAccess.Save; 表示程序集可被保存,但不能被執(zhí)行。  
                  * AssemblyBuilderAccess.RunAndSave; 表示程序集可被保存并能被執(zhí)行。
                  * AssemblyBuilderAccess.ReflectionOnly; 表示程序集只能用于反射上下文環(huán)境中,不能被執(zhí)行?!?            * AssemblyBuilderAccess.RunAndCollect; 表示程序集可以被卸載并且內(nèi)存會(huì)被回收。
                  * 
                   */
                  var assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
                  // create module builder 
                  var moduleBuilder = assemblyBuilder.DefineDynamicModule("WorldModule", "HelloWorld.exe");
      
                  // create type builder for a class Name
                  var typeBuilder = moduleBuilder.DefineType("HelloWorld", TypeAttributes.Public);
      
                  // create method buider
                  var methodBuilder = typeBuilder.DefineMethod("SayHello", MethodAttributes.Public | MethodAttributes.Static, null, null);
      
                  // get il genereator
                  var il = methodBuilder.GetILGenerator();
      
                  il.Emit(OpCodes.Ldstr, "Hello,World");
                  il.Emit(OpCodes.Call, typeof(Console).GetMethod("WriteLine", new Type[] { typeof(string) }));
                  il.Emit(OpCodes.Call, typeof(Console).GetMethod("ReadLine"));
                  il.Emit(OpCodes.Pop);
                  il.Emit(OpCodes.Ret);
      
                  var helloworldClassType = typeBuilder.CreateType();
                  assemblyBuilder.SetEntryPoint(helloworldClassType.GetMethod("SayHello"));
      
                  assemblyBuilder.Save("HelloWorld.exe");
      
                  #endregion
                  Console.WriteLine(
                           "Hi, a Hello Emit assembly has been generated for you.");
                  Console.ReadLine();
              }
          }
      }
      

深化

讀懂基礎(chǔ)的IL,在實(shí)際開發(fā)中應(yīng)用,具體實(shí)踐,留坑先

讀懂IL

  1. 讀懂加減法的IL

//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.7.2053.0
//  Copyright (c) Microsoft Corporation.  All rights reserved.



// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly demo // 指定程序集的名稱
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.

  // --- The following custom attribute is added automatically, do not uncomment -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 

  .hash algorithm 0x00008004  // 指定的hash算法
  .ver 0:0:0:0 // 指定程序集的版本
}
.module demo.exe // 指定組成程序集的模塊名稱,在此示例中,程序集中只包含一個(gè)文件
// MVID: {61F485FC-2FB2-46D9-B2EE-29E5F44AF6CA}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI //指定程序要求的應(yīng)用程序環(huán)境。在此示例中,0x0003表示該可執(zhí)行文件從控制臺(tái)運(yùn)行
.corflags 0x00000001    //  ILONLY // 當(dāng)前是元數(shù)據(jù)中的一個(gè)保留字段
// Image base: 0x05610000


// =============== CLASS MEMBERS DECLARATION ===================
/*
.class表示的Program是一個(gè)類,extends 代表Program類繼承于程序集mscorlib中的System.Object類,這就告訴我們,在C#中所有的類的父類都是Object。
private為訪問權(quán)限,表明該類是私有的。
auto:表明程序加載的時(shí)候內(nèi)存布局是有CLR決定的,而不是由程序本身控制的。
ansi:表明類的編碼為ansi編碼
beforefieldinit :表明CLR可以在第一次訪問靜態(tài)字段之前的任何時(shí)刻執(zhí)行類型構(gòu)造函數(shù)。類型構(gòu)造函數(shù)也就是構(gòu)造函數(shù),而使用beforefieldinit屬性可以提高性能。
*/
.class private auto ansi beforefieldinit ILLearning.Program
       extends [mscorlib]System.Object
{

  // main函數(shù)
  // cil managed 表明方法體中的代碼是IL代碼,且是托管代碼,即運(yùn)行在CLR運(yùn)行庫(kù)中的代碼
  // hidebysig :指令表示如果當(dāng)前類作為父類,用該指令標(biāo)記的方法將不會(huì)被子類繼承
  .method private hidebysig static void  Main(string[] args) cil managed
  {
    // .entrypoint :指令代表該函數(shù)是程序的入口函數(shù),每個(gè)托管應(yīng)用程序都有且只有一個(gè)入口函數(shù),CLR加載的時(shí)候,首先從.entrypoint函數(shù)開始執(zhí)行。
    .entrypoint
    // Code size       34 (0x22)
    // .maxstack 表明執(zhí)行構(gòu)造函數(shù)時(shí),評(píng)估堆??扇菁{數(shù)據(jù)項(xiàng)的最大個(gè)數(shù)。評(píng)估堆棧是保存方法中所需變量的值的一個(gè)內(nèi)存區(qū)域,該區(qū)域在方法執(zhí)行結(jié)束時(shí)會(huì)被清空,或者存儲(chǔ)一個(gè)返回值
    .maxstack  2
    // .locals init ([0] string helloString) 表示定義string 類型的變量,變量名成為:helloString
    .locals init (int64 V_0,
             int32 V_1,
             float32 V_2,
             int64 V_3)
    // IL_0000是代碼行的開頭。一般在IL_標(biāo)記之前的部分為變量的聲明和初始化操作。
    // IL_0000: nop 表示不做任何操作 No Operation
    IL_0000:  nop
    // (以ld為前綴的指令表示:入棧操作  st為前綴的指令則代表著出棧操作)
    IL_0001:  ldc.i4.0 // 將整數(shù)值 0 作為 int32 推送到計(jì)算堆棧上。
    IL_0002:  conv.i8 // 將位于計(jì)算堆棧頂部的值轉(zhuǎn)換為 int64。
    IL_0003:  stloc.0 // 從計(jì)算堆棧的頂部彈出當(dāng)前值并將其存儲(chǔ)到索引 0 處的局部變量列表中。
    IL_0004:  ldc.i4.2
    IL_0005:  stloc.1
    IL_0006:  ldc.r4     1. // 將所提供的 float32 類型的值作為 F (float) 類型推送到計(jì)算堆棧上。
    IL_000b:  stloc.2 
    IL_000c:  ldloc.0 //將索引 0 處的局部變量加載到計(jì)算堆棧上。 // 拿出a的值 
    IL_000d:  ldloc.1 // 拿出b的值
    IL_000e:  conv.i8 // 將b強(qiáng)制轉(zhuǎn)換成long類型
    IL_000f:  add // 相加
    IL_0010:  ldloc.2
    IL_0011:  conv.i8
    IL_0012:  add
    IL_0013:  stloc.3
    IL_0014:  ldloc.3
    // call :指令表示調(diào)用靜態(tài)函數(shù), 這里調(diào)用的是Console類中的WriteLine函數(shù),把第0個(gè)局部變量輸出到控制臺(tái)中
    IL_0015:  call       void [mscorlib]System.Console::WriteLine(int64)
    IL_001a:  nop
    IL_001b:  call       string [mscorlib]System.Console::ReadLine()
    IL_0020:  pop
    IL_0021:  ret // 返回
  } // end of method Program::Main

// 默認(rèn)的構(gòu)造函數(shù),其中.ctor 表示構(gòu)造函數(shù)
  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Program::.ctor

} // end of class ILLearning.Program


// =============================================================

// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file C:\Users\87953\Desktop\Demos\demo.res

  1. 帶有if分支的IL分析

//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.7.2053.0
//  Copyright (c) Microsoft Corporation.  All rights reserved.



// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly demo
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.

  // --- The following custom attribute is added automatically, do not uncomment -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 

  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module demo.exe
// MVID: {35CECF14-04D6-4E7E-AE4B-94F2DFB943BD}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x06EB0000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit ILLearning.Program
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // Code size       50 (0x32)
    .maxstack  2
    .locals init (int64 V_0,
             string V_1,
             bool V_2)
    IL_0000:  nop
    IL_0001:  ldc.i4.3  // 將所提供的 int32 類型的值作為 int32 推送到計(jì)算堆棧上。
    IL_0002:  conv.i8 // 轉(zhuǎn)換成long
    IL_0003:  stloc.0 // 出棧,賦值到a中
    IL_0004:  ldstr      "hello,kitty" // 字符串入棧
    IL_0009:  stloc.1  // 出棧,賦值給b
    IL_000a:  ldloc.0  //   將索引 0 處的局部變量加載到計(jì)算堆棧上。
    IL_000b:  ldc.i4.5  // 將所提供的 int32 類型的值作為 int32 推送到計(jì)算堆棧上。
    IL_000c:  conv.i8
    IL_000d:  cgt
    IL_000f:  stloc.2
    IL_0010:  ldloc.2
    /*
    * Brfalse   如果 value 為 false、空引用(Visual Basic 中的 Nothing)或零,則將控制轉(zhuǎn)移到目標(biāo)指令。
    * Brfalse.S 如果 value 為 false、空引用或零,則將控制轉(zhuǎn)移到目標(biāo)指令。
    * Brtrue    如果 value 為 true、非空或非零,則將控制轉(zhuǎn)移到目標(biāo)指令。
    * Brtrue.S  如果 value 為 true、非空或非零,則將控制轉(zhuǎn)移到目標(biāo)指令(短格式)。
    */
    IL_0011:  brfalse.s  IL_0022

    IL_0013:  nop
    IL_0014:  ldstr      "hello world"
    IL_0019:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_001e:  nop
    IL_001f:  nop
    /*
    * Br    無條件地將控制轉(zhuǎn)移到目標(biāo)指令。
    * Br.S  無條件地將控制轉(zhuǎn)移到目標(biāo)指令(短格式)。
    */
    IL_0020:  br.s       IL_002b

    IL_0022:  nop
    IL_0023:  ldloc.1
    IL_0024:  call       void [mscorlib]System.Console::WriteLine(string)
    IL_0029:  nop
    IL_002a:  nop
    IL_002b:  call       string [mscorlib]System.Console::ReadLine()
    IL_0030:  pop
    IL_0031:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Program::.ctor

} // end of class ILLearning.Program


// =============================================================

// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file C:\Users\87953\Desktop\Demos\demo2.res

  1. const會(huì)給CLR變成static

//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.7.2053.0
//  Copyright (c) Microsoft Corporation.  All rights reserved.



// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly demo
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.

  // --- The following custom attribute is added automatically, do not uncomment -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 

  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module demo.exe
// MVID: {94F20870-93B0-42E9-8F35-6716A4FE3711}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x00C30000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit ILLearning.Program
       extends [mscorlib]System.Object
{
  .class auto ansi nested assembly beforefieldinit model
         extends [mscorlib]System.Object
  {
    // Const 會(huì)給轉(zhuǎn)換成static
    .field public static literal int32 NUM = int32(0x00000003)
    .method public hidebysig specialname rtspecialname 
            instance void  .ctor() cil managed
    {
      // Code size       8 (0x8)
      .maxstack  8
      IL_0000:  ldarg.0
      IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
      IL_0006:  nop
      IL_0007:  ret
    } // end of method model::.ctor

  } // end of class model

  .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // Code size       15 (0xf)
    .maxstack  8
    IL_0000:  nop
    IL_0001:  ldc.i4.3
    IL_0002:  call       void [mscorlib]System.Console::WriteLine(int32)
    IL_0007:  nop
    IL_0008:  call       string [mscorlib]System.Console::ReadLine()
    IL_000d:  pop
    IL_000e:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Program::.ctor

} // end of class ILLearning.Program


// =============================================================

// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file C:\Users\87953\Desktop\Demos\demo3.res

  1. 裝箱和拆箱的IL

//  Microsoft (R) .NET Framework IL Disassembler.  Version 4.7.2053.0
//  Copyright (c) Microsoft Corporation.  All rights reserved.



// Metadata version: v4.0.30319
.assembly extern mscorlib
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )                         // .z\V.4..
  .ver 4:0:0:0
}
.assembly program
{
  .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) 
  .custom instance void [mscorlib]System.Runtime.CompilerServices.RuntimeCompatibilityAttribute::.ctor() = ( 01 00 01 00 54 02 16 57 72 61 70 4E 6F 6E 45 78   // ....T..WrapNonEx
                                                                                                             63 65 70 74 69 6F 6E 54 68 72 6F 77 73 01 )       // ceptionThrows.

  // --- The following custom attribute is added automatically, do not uncomment -------
  //  .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [mscorlib]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) 

  .hash algorithm 0x00008004
  .ver 0:0:0:0
}
.module program.exe
// MVID: {D837361F-CAC0-4972-821B-185D239C749A}
.imagebase 0x00400000
.file alignment 0x00000200
.stackreserve 0x00100000
.subsystem 0x0003       // WINDOWS_CUI
.corflags 0x00000001    //  ILONLY
// Image base: 0x00C40000


// =============== CLASS MEMBERS DECLARATION ===================

.class private auto ansi beforefieldinit ILLearning.Program
       extends [mscorlib]System.Object
{
  .method private hidebysig static void  Main(string[] args) cil managed
  {
    .entrypoint
    // Code size       31 (0x1f)
    .maxstack  1
    .locals init (int32 V_0,
             object V_1,
             int32 V_2)
    IL_0000:  nop
    IL_0001:  ldc.i4.1
    IL_0002:  stloc.0
    IL_0003:  ldloc.0
    IL_0004:  box        [mscorlib]System.Int32 // 裝箱
    IL_0009:  stloc.1
    IL_000a:  ldloc.1
    IL_000b:  unbox.any  [mscorlib]System.Int32 // 拆箱
    IL_0010:  stloc.2
    IL_0011:  ldloc.2
    IL_0012:  call       void [mscorlib]System.Console::WriteLine(int32)
    IL_0017:  nop
    IL_0018:  call       string [mscorlib]System.Console::ReadLine()
    IL_001d:  pop
    IL_001e:  ret
  } // end of method Program::Main

  .method public hidebysig specialname rtspecialname 
          instance void  .ctor() cil managed
  {
    // Code size       8 (0x8)
    .maxstack  8
    IL_0000:  ldarg.0
    IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
    IL_0006:  nop
    IL_0007:  ret
  } // end of method Program::.ctor

} // end of class ILLearning.Program


// =============================================================

// *********** DISASSEMBLY COMPLETE ***********************
// WARNING: Created Win32 resource file demo4.res

參考

  1. C#基礎(chǔ)拾遺系列之一:先看懂IL代碼
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容