2017-12-31 208 views
1

2つのメソッドのILをマージしようとしています:1つのメソッドが既に存在するアセンブリ(MyAssembly.dll)に由来し、1つが私のdnlibコードと同じプロジェクトにあります。両方のメソッドを読み込み、命令をマージして新しいアセンブリに書き込もうとしています。これは私が追加ただしとき、動作するかどうかの新しい方法(ので、私のプロジェクトから1)新しいアセンブリに命令を書くとき、私は例外を取得するステートメント(おそらく他のステートメント):2つのメソッドのILをマージするときに

Unhandled Exception: dnlib.DotNet.Writer.ModuleWriterException: Found some other method's instruction or a removed instruction. You probably removed an instruction that is the target of a branch instruction or an instruction that's the first/last inst 
ruction in an exception handler. 
    at dnlib.DotNet.DummyLogger.Log(Object sender, LoggerEvent loggerEvent, String format, Object[] args) 
    at dnlib.DotNet.Writer.ModuleWriterBase.dnlib.DotNet.ILogger.Log(Object sender, LoggerEvent loggerEvent, String format, Object[] args) 
    at dnlib.DotNet.Writer.MetaData.Error(String message, Object[] args) 
    at dnlib.DotNet.Writer.MetaData.dnlib.DotNet.Writer.IWriterError.Error(String message) 
    at dnlib.DotNet.Writer.MethodBodyWriter.ErrorImpl(String message) 
    at dnlib.DotNet.Writer.MethodBodyWriterBase.Error(String message) 
    at dnlib.DotNet.Writer.MethodBodyWriterBase.GetOffset(Instruction instr) 
    at dnlib.DotNet.Writer.MethodBodyWriterBase.WriteShortInlineBrTarget(BinaryWriter writer, Instruction instr) 
    at dnlib.DotNet.Writer.MethodBodyWriterBase.WriteOperand(BinaryWriter writer, Instruction instr) 
    at dnlib.DotNet.Writer.MethodBodyWriterBase.WriteInstruction(BinaryWriter writer, Instruction instr) 
    at dnlib.DotNet.Writer.MethodBodyWriterBase.WriteInstructions(BinaryWriter writer) 
    at dnlib.DotNet.Writer.MethodBodyWriter.WriteFatHeader() 
    at dnlib.DotNet.Writer.MethodBodyWriter.Write() 
    at dnlib.DotNet.Writer.MetaData.WriteMethodBodies() 
    at dnlib.DotNet.Writer.MetaData.Create() 
    at dnlib.DotNet.Writer.MetaData.CreateTables() 
    at dnlib.DotNet.Writer.ModuleWriter.WriteImpl() 
    at dnlib.DotNet.Writer.ModuleWriterBase.Write(Stream dest) 
    at dnlib.DotNet.Writer.ModuleWriterBase.Write(String fileName) 
    at dnlib.DotNet.ModuleDef.Write(String filename, ModuleWriterOptions options) 
    at dnlib.DotNet.ModuleDef.Write(String filename) 

それはしていません元のコード(MyAssembly.dllのコード)にifステートメントが含まれているときに例外をスローします。

MyAssembly.dllのコード:

string str = GameManager.m_GameVersionString; 
if (GameManager.m_Changelist != string.Empty) 
{ 
    str = str + " (" + GameManager.m_Changelist + ")"; 
} 
return str + " Release "; 

MyAssembly.dllのIL:

IL_0000: ldsfld System.String GameManager::m_GameVersionString 
IL_0005: stloc.0 
IL_0006: ldsfld System.String GameManager::m_Changelist 
IL_000B: ldsfld System.String System.String::Empty 
IL_0010: call System.Boolean System.String::op_Inequality(System.String,System.String) 
IL_0015: brfalse IL_0030 
IL_001A: ldloc.0 
IL_001B: ldstr " (" 
IL_0020: ldsfld System.String GameManager::m_Changelist 
IL_0025: ldstr ")" 
IL_002A: call System.String System.String::Concat(System.String,System.String,System.String,System.String) 
IL_002F: stloc.0 
IL_0030: ldloc.0 
IL_0031: ldstr " Release " 
IL_0036: call System.String System.String::Concat(System.String,System.String) 
IL_003B: stloc.0 
IL_003C: ldloc.0 
IL_003D: ret 

マイプロジェクトのコード:

string check = "Hello".Trim(); 

if (check == "Hello") 
{ 
    Console.WriteLine("Hello"); 
} 

マイプロジェクトのIL

IL_0000: ldstr "Hello" 
IL_0005: call System.String System.String::Trim() 
IL_000A: ldstr "Hello" 
IL_000F: call System.Boolean System.String::op_Equality(System.String,System.String) 
IL_0014: brfalse.s IL_0020 
IL_0016: ldstr "Hello" 
IL_001B: call System.Void System.Console::WriteLine(System.String) 
IL_0020: ret 

ザ・ILは、私がdnSpyで生成されたILと同じに見える合併

IL_0000: ldstr "Hello" 
IL_0005: call System.String System.String::Trim() 
IL_000A: ldstr "Hello" 
IL_000F: call System.Boolean System.String::op_Equality(System.String,System.String) 
IL_0014: brfalse.s IL_0020 
IL_0016: ldstr "Hello" 
IL_001B: call System.Void System.Console::WriteLine(System.String) 
IL_0020: ldsfld System.String GameManager::m_GameVersionString 
IL_0025: stloc.0 
IL_0026: ldsfld System.String GameManager::m_Changelist 
IL_002B: ldsfld System.String System.String::Empty 
IL_0030: call System.Boolean System.String::op_Inequality(System.String,System.String) 
IL_0035: brfalse.s IL_004D 
IL_0037: ldloc.0 
IL_0038: ldstr " (" 
IL_003D: ldsfld System.String GameManager::m_Changelist 
IL_0042: ldstr ")" 
IL_0047: call System.String System.String::Concat(System.String,System.String,System.String,System.String) 
IL_004C: stloc.0 
IL_004D: ldloc.0 
IL_004E: ldstr " Release " 
IL_0053: call System.String System.String::Concat(System.String,System.String) 
IL_0058: stloc.0 
IL_0059: ldloc.0 
IL_005A: ret 

IL

合併:ファイルにマージされたILを書くとき https://owo.whats-th.is/a0783e.png

ただし、エラーがスローされます。私のコード:

//Patch method 

... 

var patchModule = ModuleDefMD.Load(patchClass.Module); 
var patchMethod = FindMethod(patchModule, patchClass, method.Name); 

var assemblyModule = ModuleDefMD.Load(assemblyPath); 
var assemblyMethod = FindMethod(assemblyModule, attribute.Type, attribute.MethodName, attribute.Parameters); 

assemblyMethod.Body = MergeMethods(patchMethod, assemblyMethod, attribute.CodeMode, attribute.CustomPos); 

assemblyModule.Write(finalPath); //Error is thrown here 

... 

private static CilBody MergeMethods(MethodDef original, MethodDef target, AmityPatch.Mode mode, int mergeLoc = 0) 
{ 

    original.FreeMethodBody(); 
    target.FreeMethodBody(); 

    var originalBody = original.Body; 
    var targetBody = target.Body; 

    var targetModule = target.Module; 

    var originalInstructions = originalBody.Instructions; 
    var targetInstructions = targetBody.Instructions; 

    Console.WriteLine("=original method="); 
    Console.WriteLine(); 
    foreach (var originalInstruction in originalInstructions) 
    { 
     Console.WriteLine(originalInstruction); 
    } 
    Console.WriteLine(); 
    Console.WriteLine("=target method="); 
    Console.WriteLine(); 
    foreach (var targetInstruction in targetInstructions) 
    { 
     Console.WriteLine(targetInstruction); 
    } 

    RemoveReturn(ref originalInstructions, true); 
    if (mode == AmityPatch.Mode.Postfix) mergeLoc = targetInstructions.Count - 1; 

    var localOffset = targetBody.Variables.Count; 

    for (var i = 0; i < originalBody.Variables.Count; i++) 
    { 
     targetBody.Variables.Add(
      new Local(originalBody.Variables[i].Type, originalBody.Variables[i].Name)); 
    } 

    for (var i = originalInstructions.Count - 1; i >= 0; i--) 
    { 
     var o = originalInstructions[i]; 
     var c = new Instruction(o.OpCode, o.Operand); 

     switch (o.Operand) 
     { 
      case IType type: 
       c.Operand = targetModule.Import(type); 
       break; 
      case IMethod method: 
       c.Operand = targetModule.Import(method); 
       break; 
      case IField field: 
       c.Operand = targetModule.Import(field); 
       break; 
     } 

     if (IsStloc(o.OpCode)) 
     { 
      c.OpCode = OpCodes.Stloc; 
      c.Operand = targetBody.Variables[StlocIndex(o) + localOffset]; 
     } 
     else if (IsLdloc(o.OpCode)) 
     { 
      c.OpCode = OpCodes.Ldloc; 
      c.Operand = targetBody.Variables[LdlocIndex(o) + localOffset]; 
     } 
     else if (IsLdloca(o.OpCode)) 
     { 
      c.OpCode = OpCodes.Ldloca; 
      c.Operand = targetBody.Variables[LdlocIndex(o) + localOffset]; 
     } 

     targetInstructions.Insert(mergeLoc, c); 
    } 

    targetBody.OptimizeMacros(); 
    targetBody.OptimizeBranches(); 

    Console.WriteLine(); 
    Console.WriteLine("=merged method="); 
    Console.WriteLine(); 

    foreach (var instruction in targetBody.Instructions) 
    { 
     Console.WriteLine(instruction); 
    } 

    Console.WriteLine(targetBody.Variables.Count); 

    return targetBody; 
} 

この問題の原因はわかりません。 ILのすべてのラベルは正しいようです。 if文を削除すると、dnlibはILをアセンブリに書き込みます。

+0

私はライブラリのバグのような臭いがありますので、[新しい問題ボタン](https://github.com/0xd4d/dnlib/issues)をクリックすることを検討してください。 –

答えて

0

元のターゲットメソッド、マージするメソッド、および結果のメソッドボディからILバイトを共有できますか?マージするメソッドが異なるアセンブリからのものである場合、トークンを作成/変換する必要があります。

関連する問題