在运行时修改导致InvalidProgramException的IL代码

时间:2018-06-11 11:18:23

标签: c# .net intermediate-language ildasm ilasm

我试图删除IL代码中的Tick事件的订阅,以便它不会触发。

这是IL代码:

IL_0e19:  ldftn      instance void App.Framework.MainForm::mTimer_Tick(object, class [mscorlib]System.EventArgs)
IL_0e1f:  newobj     instance void [mscorlib]System.EventHandler::.ctor(object, native int)
IL_0e24:  callvirt   instance void [System.Windows.Forms]System.Windows.Forms.Timer::add_Tick(class [mscorlib]System.EventHandler)
IL_0e29:  ldarg.0

所以我想我应该能够删除最后2行以删除订阅,它应该没问题。

IL_0e24:  callvirt   instance void [System.Windows.Forms]System.Windows.Forms.Timer::add_Tick(class [mscorlib]System.EventHandler)
IL_0e29:  ldarg.0

我用以下代码成功编译了IL代码:

ilasm.exe c:\Framework.il /32bitpreferred /dll

现在,当我尝试启动该程序时,它会抛出异常:

System.InvalidProgramException: JIT Compiler encountered an internal limitation.

如果我在没有任何修改的情况下编译IL,那么程序运行时没有任何异常,因此它正在进行更改。

1 个答案:

答案 0 :(得分:4)

ldarg0无关,可能与下一个操作有关;所以你不应该放弃它。你还在堆栈上留下了一些东西,所以你应该弹出两个值 - 目标实例(加载未显示),而不是删除 callvirt。和事件处理程序实例(来自ldftn / newobj - 请注意,此处还显示了与此步骤相关的未显示的负载)。或者 - 首先不要加载这两个值。可能在IL_0e19之前发生了很多事情,可能会有一些清理工作。

基本上,给定代码如:

someTimer.Tick += target.SomeMethod;

这是:

  • 加载someTimer [stack now someTimer]
  • 加载目标[stack now someTimer,target]
  • 将SomeMethod加载为函数指针[stack now someTimer,target,function pointer]
  • 为该对象/指针创建一个委托[stack now someTimer,delegate]
  • 虚拟调用Tick_add方法[stack now empty]

您显示的IL开始于"将SomeMethod加载为函数指针",并包含用于下一操作的无关负载。