CLR IL-在.locals init上的方括号的重要性

时间:2013-09-23 17:36:11

标签: reflection.emit il ildasm

我正在尝试使用Reflection& amp;生成动态装配。在.NET中发出。我收到一个错误,“Common Language Runtime检测到一个无效的程序。”我创建了另一个程序,它具有我想要的功能,使用硬编码类型。我试图编写的功能最终将使用动态类型,但我可以使用ILDasm来查看我需要生成的IL。我正在将我生成的IL与编译器生成的IL进行比较。在一个方法的.locals init声明中,我看到编译器生成的代码中有一个额外的项,

编译生成:

.locals init ([0] class [System.Core]System.Linq.Expressions.ParameterExpression CS$0$0000,
           [1] class [System.Core]System.Linq.Expressions.ParameterExpression[] CS$0$0001)
我的:

.locals init (class [System.Core]System.Linq.Expressions.ParameterExpression V_0,  
       class [System.Core]System.Linq.Expressions.ParameterExpression[] V_1)

我不理解编译器生成的代码中“[0]”和“[1]”的重要性。谁能告诉我这是什么意思?

作为一个更普遍的问题,我可以毫不费力地遵循大多数ILDasm输出。但我经常遇到一个有问题的表达。例如,在ILDasm的这一行

callvirt   instance class [EntityFramework]System.Data.Entity.ModelConfiguration.EntityTypeConfiguration`1<!!0> [EntityFramework]System.Data.Entity.DbModelBuilder::Entity<class DynamicEdmxTrial.HardFooAsset>()
“!! 0”可能是指Entity&lt;&gt;的泛型类型,但我不确定,我想知道ILDasm输出是否有一个键可以解释其更加模糊的输出我

1 个答案:

答案 0 :(得分:1)

该规范免费提供here。它需要一点点习惯,但一旦你弄清楚结构,很容易找到大部分细节。

!!列在 II.7.1类型

Type ::=       | Description                             | Clause
  ‘!’ Int32    | Generic parameter in a type definition, | §II.9.1
               | accessed by index from 0                |
| ‘!!’ Int32   | Generic parameter in a method           | §II.9.2
               | definition, accessed by index from 0    |
...

换句话说,在C#调用f<T, U>()的方法中,!!0T!!1U

然而,[0]是一个很好的问题。该规范似乎没有解决它。 II.15.4.1.3 .locals指令中描述了.locals指令,该指令将语法列为

MethodBodyItem ::= ...
 | .locals [ init ] ‘(’ LocalsSignature ‘)’
LocalsSignature ::= Local [ ‘,’ Local ]*
Local ::= Type [ Id ]

除非它是[0]的一部分,否则似乎没有任何内容允许TypeType不允许任何以[开头的内容。我的猜测是,这是一个特定于Microsoft实现的无证特性,旨在帮助人类读者看到位置0是局部变量CS$0$0000,以便生成的指令通过索引访问局部变量。

试验ILAsm表明这正是它的意思。采用简单的C#程序:

static class Program {
    static void Main() {
        int i = 0, j = 1;
    }
}

并编译然后将其反汇编(csc test.cs && ildasm /text test.exe >test.il)显示:

....
.locals init (int32 V_0,
         int32 V_1)
IL_0000:  nop
IL_0001:  ldc.i4.0
IL_0002:  stloc.0
IL_0003:  ldc.i4.1
IL_0004:  stloc.1
IL_0005:  ret
....

.locals修改为

.locals init ([0] int32 V_0, [0] int32 V_1)

提供了一条有用的警告信息:

test.il(41) : warning : Local var slot 0 is in use

确实,声明不同类型的变量,然后使用[2][1][0]对它们进行重新排序,汇编并立即反汇编结果,表明变量已重新排序。