Csharp/C#教程:基于反汇编简单C#代码的手工编码IL的问题分享


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

我刚开始看一下IL,我很好奇我的尝试(如下所示)从编译器的输出中删除多余的代码有任何意想不到的副作用。

关于结果的几个问题:

  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 } 

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

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

现在具体到您的问题:

原始操作中nop操作的目的是什么?

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

原始方法结束时br.s的目的是什么?

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

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

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

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

重写版本是否以任何方式不正确?

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

免责声明:无论如何,我不是IL专家。

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

    不久前在programmers.stackexchange.com上对x86 ASM进行了大量讨论,请参阅此处: NOP指令的目的和x86汇编中的align语句 。 它基本上是一样的。

  2. 原始方法结束时br.s的目的是什么?

    这只是方法结束的一个分支。 如果你在这个函数中有多个返回路径,那么查看它会更有意义。 就目前而言,编译器已经包含它而不是优化它(可能编译器开关会优化它)。

  3. 重写版本是否以任何方式不正确?

    不是我能看到的。 您刚刚剥离了编译器的大部分工作,这对于这样一个简单的应用程序来说并不是必需的。 如果您要对此代码进行任何进一步的添加,则需要额外的IL来完成它的任务。

    上述就是C#学习教程:基于反汇编简单C#代码的手工编码IL的问题分享的全部内容,如果对大家有所用处且需要了解更多关于C#学习教程,希望大家多多关注—计算机技术网(www.ctvol.com)!

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/cdevelopment/1027763.html

(0)
上一篇 2022年1月10日
下一篇 2022年1月10日

精彩推荐