2012-10-07 62 views

回答

8

下面是如何注入最後。

首先你需要修復你的返回語句。你只需要一個。

Instruction FixReturns() 
{ 
    if (Method.ReturnType == TypeSystem.Void) 
    { 
     var instructions = body.Instructions; 
     var lastRet = Instruction.Create(OpCodes.Ret); 
     instructions.Add(lastRet); 

     for (var index = 0; index < instructions.Count - 1; index++) 
     { 
      var instruction = instructions[index]; 
      if (instruction.OpCode == OpCodes.Ret) 
      { 
       instructions[index] = Instruction.Create(OpCodes.Leave, lastRet); 
      } 
     } 
     return lastRet; 
    } 
    else 
    { 
     var instructions = body.Instructions; 
     var returnVariable = new VariableDefinition("methodTimerReturn", Method.ReturnType); 
     body.Variables.Add(returnVariable); 
     var lastLd = Instruction.Create(OpCodes.Ldloc, returnVariable); 
     instructions.Add(lastLd); 
     instructions.Add(Instruction.Create(OpCodes.Ret)); 

     for (var index = 0; index < instructions.Count - 2; index++) 
     { 
      var instruction = instructions[index]; 
      if (instruction.OpCode == OpCodes.Ret) 
      { 
       instructions[index] = Instruction.Create(OpCodes.Leave, lastLd); 
       instructions.Insert(index, Instruction.Create(OpCodes.Stloc, returnVariable)); 
       index++; 
      } 
     } 
     return lastLd; 
    } 
} 

然後找到第一條指令。如果它是一個實例構造函數,則需要跳過2。

Instruction FirstInstructionSkipCtor() 
{ 
    if (Method.IsConstructor && !Method.IsStatic) 
    { 
     return body.Instructions.Skip(2).First(); 
    } 
    return body.Instructions.First(); 
} 

然後縫合它一起

void InnerProcess() 
{ 
    body = Method.Body; 
    body.SimplifyMacros(); 
    ilProcessor = body.GetILProcessor(); 

    var returnInstruction = FixReturns(); 

    var firstInstruction = FirstInstructionSkipCtor(); 

    var beforeReturn = Instruction.Create(OpCodes.Nop); 
    ilProcessor.InsertBefore(returnInstruction, beforeReturn); 

    InjectIlForFinaly(returnInstruction); 

    var handler = new ExceptionHandler(ExceptionHandlerType.Finally) 
     { 
      TryStart = firstInstruction, 
      TryEnd = beforeReturn, 
      HandlerStart = beforeReturn, 
      HandlerEnd = returnInstruction, 
     }; 

    body.ExceptionHandlers.Add(handler); 
    body.InitLocals = true; 
    body.OptimizeMacros(); 
} 
+0

因此,它基本上與該文章中描述的過程相同,只是將ExceptionHandlerType.Finally傳遞到新的ExceptionHandler()中。如果你想要try/catch/finally,你需要創建兩個「ExceptionHandler」實例並將它們添加到方法中,一個用於catch,一個用於finally。如果是這樣的話,那麼這些名字肯定會讓人困惑,因爲你並沒有真正創建新的異常處理程序,至少對於'finally'來說。感謝指針。 – naasking

1

實測值所檢查的例子相當的信息和是有用的。雖然在更復雜的條件下遇到了問題。在FixReturns()中,無論是無效的還是無效的返回範圍,更改ret的方法 - >通過創建新的指令孤立原來的方法。這可以將其他指令與孤兒作爲操作數(例如,分支到原始ret)。最終的代碼最終會失效。

我們只是簡單地更新了現有的ret指令的操作碼/操作數對與創建新操作碼對,並且都顯得很好。

乾杯。