关于手工编码IL问题基础上拆卸简单的C#代码(Questions about hand coded

2019-09-23 06:13发布

我刚开始看IL一点,我很好奇,如果我尝试(如下图所示),从编译器的输出有任何意外的副作用去除多余的代码。

一对夫妇对结果quesiton的:

  1. 什么是在原NOP操作的目的是什么?
  2. 什么是br.s在在原来的方法到底目的何在?
  3. 是重新编写的版本不正当以任何方式?

原来C#代码:

class Program {
    public static int Main() {
        return Add(1, 2);
    }
    public static int Add(int a, int b) {
        return a + b;
    }
}

编译csc.exe与拆卸它ildasm.exe (原文):

  .method public hidebysig static int32  Main() cil managed
  {
    .entrypoint
    .maxstack  2
    .locals init (int32 V_0)
    IL_0000:  nop
    IL_0001:  ldc.i4.1
    IL_0002:  ldc.i4.2
    IL_0003:  call       int32 Program::Add(int32, int32)
    IL_0008:  stloc.0
    IL_0009:  br.s       IL_000b
    IL_000b:  ldloc.0
    IL_000c:  ret
  } 
  .method public hidebysig static int32  Add(int32 a,
                                             int32 b) cil managed
  {
    .maxstack  2
    .locals init (int32 V_0)
    IL_0000:  nop
    IL_0001:  ldarg.0
    IL_0002:  ldarg.1
    IL_0003:  add
    IL_0004:  stloc.0
    IL_0005:  br.s       IL_0007
    IL_0007:  ldloc.0
    IL_0008:  ret
  }

重新写入(产生相同的输出):

  .method public hidebysig static int32  Main() cil managed
  {
    .entrypoint
        .maxstack  2
    ldc.i4.1
    ldc.i4.2
    call int32 Program::Add(int32, int32)
    ret
  }

  .method public hidebysig static int32  Add(int32 a, int32 b) cil managed
  {
    .maxstack  2
      ldarg.0
      ldarg.1
    add
    ret
  }

Answer 1:

你看到所有的“多余”的代码是特定于调试版本(通常被优化掉的发布版本),并允许您执行的东西,你不能在发行版本通常做。

调试生成的代码是这样的,它允许最大的独立性在调试会话过程中设置断点和更改/检查堆栈值。 也IL代码应该尽可能模仿的高级代码,使得每一个“原因”和“效果”可以被映射到较高级别代码行。

现在要具体到你的问题:

什么是在原NOP操作的目的是什么?

NOP允许你在未“执行”的地方设置断点。 对于如法,循环语句,或者如果打开括号。 在这些非可执行的指令,打破在开括号,可以修改/只有一个街区开始之前检查堆栈(但无可否认,你可以通过在块的执行的第一线断裂,而不是左括号很容易实现这一点,但它还可以让你在开括号打破的独立性)

什么是br.s在在原来的方法到底目的何在?

看着原来的代码,你会发现它是没有意义的,以“跳”到下一行,而不是允许代码自然“秋天”到下一行。 但它读作:

“以调试版本,每当一个方法需要返回,则跳转到方法的结束时,从读出堆栈的返回值,然后返回该值”

因此,它提供什么优势调试?

如果你在你的代码不止一个return语句,从堆栈读取返回值之前他们都将“跳”到代码的末尾。 这使您只有一个地方(该方法的右大括号),在那里你可以把一个破发点,并修改返回值,之前它实际上是返回给调用方法。 非常有益的,不是吗?

是重新编写的版本不正当以任何方式?

没有什么不当在你的代码。 事实上,如果你建立在释放模式的原件和校验所生成CIL,你会发现,它主要是和你一样。



Answer 2:

免责声明:我不是以任何方式的IL专家。

  1. 什么是NOP操作的目的是什么?

    有前一阵在programmers.stackexchange.com 86 ASM方面关于这个的大讨论,在这里看到: NOP指令的目的和x86汇编对准发言 。 这将基本上是相同的。

  2. 什么是br.s在在原来的方法到底目的何在?

    这仅仅是该方法的最后一个分支。 如果你要在这个函数的多个返回路径它会更有意义来看待。 既然这样,编译器已经包括它,而不是优化它带走的(可能是一个编译器开关将优化它扔掉)。

  3. 是重新编写的版本不正当以任何方式?

    这并不是说我可以看到。 您刚刚剥离了大部分的编译器的工作指出,不需要这样一个简单的应用程序。 如果你要作进一步的补充,这个代码,然后在这里多余的IL将被要求完成它的任务。



文章来源: Questions about hand coded IL based on disassembled simple C# code
标签: c# il