C#语句可以生成非连接的MSIL

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C#语句可以生成非连接的MSIL相关的知识,希望对你有一定的参考价值。

问题是关于C# language specificationCIL language specification,以及Microsoft和Mono的C#编译器行为。

我正在构建一些代码分析工具(无论如何),它们在CIL上运行。

考虑到一些代码示例,我注意到代码语句(try / catch,ifelse,ifthen,loops,...)生成MSIL的连接块。

但我想确定我不能编写产生非连接MSIL的C#代码构造。更具体地说,我可以编写任何转换为​​(类似)的C#statement

IL_0000: 
IL_0001: 
IL_0002: 

// hole

IL_001a: 
IL_001b:

我已经尝试过使用goto和嵌套循环的一些奇怪的东西,但也许我不像一些用户那样疯狂。

答案

当然,这很简单。就像是:

static void M(bool x)
{
    if (x)
        return;
    else
        M(x);
    return;
}

如果你在调试模式下编译它,你得到

    IL_0000: nop
    IL_0001: ldarg.0
    IL_0002: stloc.0
    IL_0003: ldloc.0
    IL_0004: brfalse.s IL_0008
    IL_0006: br.s IL_0011
    IL_0008: ldarg.0
    IL_0009: call void A::M(bool)
    IL_000e: nop
    IL_000f: br.s IL_0011
    IL_0011: ret

if声明从00010009,而if的结果是0011的结果;两个return语句都是相同的代码,所以有一个“洞”包含nopif主体和结果之间的无条件分支。

更一般地说,你不应该对C#编译器生成的IL的布局做任何假设。除了IL产生的IL合法且安全,可验证之外,编译器不做任何其他保证。


你说你正在编写一些代码分析工具;作为C#分析器重要部分的作者,以及在Coverity从事第三方分析工具的人,提出建议:对于您通常想要回答C#程序的大多数问题,Roslyn生成的解析树是您希望分析的实体,而不是IL。解析树是一个具体的语法树;它与源代码中的每个字符都是一对一的。将优化的IL映射回原始源代码可能非常困难,并且在IL分析中很容易产生误报。

换句话说:源到IL是语义保留但信息丢失;您通常希望分析其中包含最多信息的工件。

如果由于某种原因必须在IL级别操作分析器,那么您的首要任务应该是找到基本块的边界,特别是在分析可达性属性时。

“基本块”是IL的连续块,其中块的端点不“继续”到下面的指令 - 因为它是例如分支,返回或抛出 - 并且没有分支到块除了第一条指令以外的任何地方。

然后,您可以为每种方法形成基本块的图形,指示哪些方法可以将控制转移到哪些其他块。这“提高了分析的水平”;现在你要分析基本块图的效果,而不是分析一系列IL指令的效果。

如果你说更多关于你正在做什么样的分析,我可以进一步建议。

另一答案

理论上是(这来自我的经验)。您的分析工具不直接处理c#,但仅适用于IL代码。 IL可以由任何人制作,不仅可以由visual studio制作,也可以由visual basic,python等其他语言编译器制作。网...和混淆器!混淆器是真正的罪魁祸首:当其他编译器试图遵守规范时,混淆器会尽力利用规范和目标运行时。

混淆的代码可能违反某些常识模式。考虑这种情况:某些智能混淆器产生非法的msil,但是抖动消化它,因为它发生了无效部分最终没有被执行。

在构建分析工具时,除非您的目标是构建反混淆器,否则无法处理这些情况。

以上是关于C#语句可以生成非连接的MSIL的主要内容,如果未能解决你的问题,请参考以下文章

MSIL 静态类在 IL 定义上和非静态类的差别

使用MSIL采用Emit方式实现C#的代码生成与注入

MSIL实用指南-类相关生成

MSIL实用指南-字段的加载和保存

学习 CIL (MSIL) 的最佳资源是啥

如何查看 C# 编译器生成的 MSIL / CIL?为啥叫组装?