2017-12-31 42 views
1

두 가지 메서드의 IL을 병합하려고합니다. 하나는 기존 어셈블리 (MyAssembly.dll)의 메서드이고 다른 하나는 내 dnlib 코드와 동일한 프로젝트에 있습니다. 두 가지 방법을 모두 읽고 지침을 병합 한 다음 새 어셈블리에 쓰려고합니다. 이것은 내가 추가 그러나 때, 작동하는 경우, 새로운 방법 (나의 프로젝트의 하나) 새로운 어셈블리에 지시를 쓸 때 나는 예외를 얻을 문 (아마 다른 문) :두 메서드의 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 문이 포함되어 있으면 예외가 throw됩니다.

하여 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 
,536 파일에 병합 된 IL를 작성할 때 https://owo.whats-th.is/a0783e.png

는하지만, 오류가 발생합니다 : 91,363,210

내가 dnSpy 생성 IL은 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 

일리노이

합병. 내 코드 :

//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; 
} 

이 문제의 원인은 무엇인지 알 수 없습니다. 일리노이의 모든 레이블이 정확하다고 보입니다. if 문을 제거 할 때 dnlib는 일리노이를 어셈블리에 잘 작성합니다.

+0

도서관 버그와 같은 냄새가 나에게는 [New Issue button] (https://github.com/0xd4d/dnlib/issues)을 클릭하십시오. –

답변

0

원본 대상 메서드, 병합 할 메서드 및 결과 메서드 본문에서 IL 바이트를 공유 할 수 있습니까? 병합 할 메소드가 다른 어셈블리의 메소드 인 경우 토큰을 작성/변환해야 할 수 있습니다.

관련 문제