如何删除cecil指令

时间:2013-01-02 18:49:57

标签: .net mono mono.cecil

我有这个方法:

public int Test()
{
    ExternalClass cls = new ExternalClass();
    return cls.ExternalMethod();
}

我需要使用IL Injection更改它,因此我可以将类型作为参数传递并删除直接对象创建,如下所示:

public int Test(ExternalClass cls)
{

    return cls.ExternalMethod();
}

我可以使用<> .Parameters.Add( _ ___ )添加其他参数,并生成新的程序集。

问题是我无法删除新对象创建的指令。以下是我用来删除它的行。

ILProcessor ilProcessor = <<MethodDefinition>>.Body.GetILProcessor();
ilProcessor.Remove(<<newobj instruction>>);

一旦我尝试调用如下所示的修改后的汇编方法,就会抛出错误“Common Language Runtime检测到无效程序。”

ExternalClass ext = new ExternalClass();
int i = prg1.Test(ext);

我知道我可能也需要处理内存分配相关的东西。如果有人能够在这里提供额外的步骤,我将不胜感激。

1 个答案:

答案 0 :(得分:6)

您不能只删除newobj指令;你留下了一个无效的程序,正如运行时告诉你的那样。这里大致是原始方法如何转换为IL:

public Int32 Test()
{
    .local ExternalClass 0;

    // ExternalClass cls = new ExternalClass();
    newobj class ExternalClass();
    stloc.0;

    // return cls.ExternalMethod();
    ldloc.0;
    callvirt Int32 class ExternalClass:ExternalMethod();
    ret;
}

如果仅删除newobj指令,则stloc指令将不会在堆栈中存储任何内容以存储在本地。您需要将方法转换为:

public Int32 Test(ExternalClass cls)
{
    // return cls.ExternalMethod();
    ldarg.1;
    callvirt Int32 class ExternalClass:ExternalMethod();
    ret;
}

所以你需要做三件事:

  1. 将参数添加到方法签名
  2. 删除的所有内容,包括 ldloc指令。
  3. 在方法的开头插入ldarg.1指令。
  4. 或者,您也可以删除ExternalClass本地邮件。 (这将由JIT编译器优化,但会使IL图像膨胀。)