如何识别将传递给Mono.Cecil中的特定IL方法调用的参数

时间:2016-02-13 13:23:50

标签: c# .net il mono.cecil

我正在使用Mono.Cecil对程序集进行一些分析和重写。在某些情况下,这很简单:您可以在调用之前查看,以查看参数的加载位置:

// Math.Pow(2, 4)
IL_0001:  ldc.r8      00 00 00 00 00 00 00 40 
IL_000A:  ldc.r8      00 00 00 00 00 00 10 40 
IL_0013:  call        System.Math.Pow

然而,当函数的参数本身是复杂的表达式时,这会变得更复杂:

// Math.Pow(2, Math.Abs(Math.Max(17, "123".GetHashCode())));
IL_0001:  ldc.r8      00 00 00 00 00 00 00 40 
IL_000A:  ldc.i4.s    11 
IL_000C:  ldstr       "123"
IL_0011:  callvirt    System.Object.GetHashCode
IL_0016:  call        System.Math.Max
IL_001B:  call        System.Math.Abs
IL_0020:  conv.r8     
IL_0021:  call        System.Math.Pow

在这种情况下,在加载第一个参数和加载第二个参数之间会发生一堆事情。我想知道:Mono.Cecil是否公开了任何工具来查找负责推送每个参数的IL指令?

1 个答案:

答案 0 :(得分:2)

ILSpy是基于Cecil的C#反编译器的开源IL,它也可以用作a library called ICSharpCode.Decompiler。它可以将IL转换为" IL AST",我认为这正是您所要求的。

如果你这样使用它:

var decompiled = new ILAstBuilder().Build(method, true, new DecompilerContext(module));
var block = new ILBlock(decompiled);
new ILInlining(block).InlineAllVariables();

然后对于以下方法(在发布模式下编译):

static double F()
{
    return Math.Pow(2, Math.Abs(Math.Max(17, "123".GetHashCode())));
}

变量block将包含:

ret(call(Math::Pow, ldc.r8(2), conv.r8(call(Math::Abs, call(Math::Max, ldc.i4(17), callvirt(object::GetHashCode, ldstr("123")))))));

请注意,我没有使用ICSharpCode.Decompiler的经验,因此可能有更好的方法来执行此操作。