CIL中的nop有什么意义

时间:2013-10-06 07:24:21

标签: c# cil

所以我在C#中编写了以下代码。

class Test
{
    int a;
    System.IO.StreamReader reader;

    public Test()
    {
        a = 5;
        reader = new System.IO.StreamReader(String.Empty);
    }
}

IL中类的构造函数看起来像这样

.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // Code size       33 (0x21)
  .maxstack  8
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  nop
  IL_0007:  nop
  IL_0008:  ldarg.0
  IL_0009:  ldc.i4.5
  IL_000a:  stfld      int32 Test2.Test::a
  IL_000f:  ldarg.0
  IL_0010:  ldsfld     string [mscorlib]System.String::Empty
  IL_0015:  newobj     instance void [mscorlib]System.IO.StreamReader::.ctor(string)
  IL_001a:  stfld      class [mscorlib]System.IO.StreamReader Test2.Test::reader
  IL_001f:  nop
  IL_0020:  ret
} // end of method Test::.ctor

有3个nop命令。 (据我所知,这表示无操作)。这些命令的需要是什么。我的意思是,如果根本没有命令而不是nop

,会有什么区别

2 个答案:

答案 0 :(得分:18)

C#编译器在为程序写入.pdb文件时使用它们。其中包含调试信息,其中包含代码的文件+行号信息。调试器使用它来查找需要注入INT 3指令的机器代码,以便在设置断点时让程序停止执行。抖动为MSIL中的每个Opcodes.Nop发出NOP机器代码指令。

public Test()上设置断点时使用第一个nop。请注意,在基础构造函数调用之后注入,以便变量在Auto / Locals / Watch调试窗口中变为有效。

在第一个{花括号上设置断点时使用第二个nop。该行根本不生成任何代码,因此非常需要伪造的MSIL指令。

第三个nop的相同故事,为最后一个}大括号生成。当您在该断点上设置断点时,您可以检查方法返回值(如果有)。在Debug + Windows + Registers窗口中间接可见。在VS2013中得到改进。

因此,这只是帮助调试程序,它们使断点可以预测。在构建程序的Release配置时,会生成 not 的NOP。 C#项目具有Debug和Release配置的一个重要原因。你仍然可以调试一个Release版本,但这是一个相当混乱的体验,让你怀疑你的理智:)

答案 1 :(得分:3)

它们用于在调试模式下构建时支持断点,并且对程序集的执行没有任何影响。