두 가지 메서드의 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는 일리노이를 어셈블리에 잘 작성합니다.
도서관 버그와 같은 냄새가 나에게는 [New Issue button] (https://github.com/0xd4d/dnlib/issues)을 클릭하십시오. –