基于反汇编的简单C#代码的手工编码IL的问题

前端之家收集整理的这篇文章主要介绍了基于反汇编的简单C#代码的手工编码IL的问题前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我刚开始看一下IL,我很好奇我的尝试(如下所示)从编译器输出删除多余的代码有任何意想不到的副作用.

关于结果的几个问题:

>原作中nop操作的目的是什么?
>原始方法结束时br.s的目的是什么?
>重写版本是否以任何方式不正确?

原始C#代码

  1. class Program {
  2. public static int Main() {
  3. return Add(1,2);
  4. }
  5. public static int Add(int a,int b) {
  6. return a + b;
  7. }
  8. }

用csc.exe编译并用ildasm.exe(原始版本)反汇编:

  1. .method public hidebysig static int32 Main() cil managed
  2. {
  3. .entrypoint
  4. .maxstack 2
  5. .locals init (int32 V_0)
  6. IL_0000: nop
  7. IL_0001: ldc.i4.1
  8. IL_0002: ldc.i4.2
  9. IL_0003: call int32 Program::Add(int32,int32)
  10. IL_0008: stloc.0
  11. IL_0009: br.s IL_000b
  12. IL_000b: ldloc.0
  13. IL_000c: ret
  14. }
  15. .method public hidebysig static int32 Add(int32 a,int32 b) cil managed
  16. {
  17. .maxstack 2
  18. .locals init (int32 V_0)
  19. IL_0000: nop
  20. IL_0001: ldarg.0
  21. IL_0002: ldarg.1
  22. IL_0003: add
  23. IL_0004: stloc.0
  24. IL_0005: br.s IL_0007
  25. IL_0007: ldloc.0
  26. IL_0008: ret
  27. }

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

  1. .method public hidebysig static int32 Main() cil managed
  2. {
  3. .entrypoint
  4. .maxstack 2
  5. ldc.i4.1
  6. ldc.i4.2
  7. call int32 Program::Add(int32,int32)
  8. ret
  9. }
  10.  
  11. .method public hidebysig static int32 Add(int32 a,int32 b) cil managed
  12. {
  13. .maxstack 2
  14. ldarg.0
  15. ldarg.1
  16. add
  17. ret
  18. }

解决方法

您看到的所有“多余”代码都特定于调试版本(通常会针对发布版本进行优化),并允许您执行在发布版本中通常无法执行的操作.

调试构建代码使得它在调试会话期间允许最大程度地独立设置断点和更改/检查堆栈值.此外,IL代码应尽可能模仿更高级别的代码,以便每个“原因”和“效果”都可以映射到更高级别的代码行.

现在具体到您的问题:

What is the purpose of the nop operations in the original?

NOP允许您在未执行的位置设置断点.对于例如方法,循环或if语句的开括号.在这些不可执行的指令中,在开始大括号中断,允许您在块开始之前修改/检查堆栈(尽管可以肯定的是,您可以通过在块的第一行执行而不是打开大括号来轻松实现这一点,但它仍然允许你在开口支架上打破独立)

What is the purpose of the br.s at the end of the methods in the original?

查看原始代码,您可能会发现“跳转”到下一行是没有意义的,而不是让代码自然地“下降”到下一行.但请将其读作:

“在调试版本中,只要方法需要返回,跳转方法的末尾,从堆栈中读取返回值,然后返回值”

那么它为调试提供了什么优势呢?

如果代码中有多个return语句,那么在从堆栈中读取返回值之前,它们都会“跳转”到代码的末尾.这允许您只有一个位置(方法的右括号),您可以在其中放置断点并在实际返回到调用方法之前修改返回值.非常有帮助不是吗?

Is the re-written version improper in any way?

您的代码中没有任何不当之处.实际上,如果您在发布模式下构建原始文件并检查生成的CIL,您会发现它与您的大多数相同.

猜你在找的C#相关文章