C# Harmony补丁中如何比较CodeInstruction.Labels与已知Label值?
问题解答
明确一点:.NET原生的System.Reflection.Emit.Label没有直接从IL偏移量字符串(比如"IL_0067")创建实例的方法。因为Label是和特定ILGenerator绑定的不透明标识,内部关联的是IL生成过程中的位置信息,而非最终编译后的字符串偏移量。
要实现你替换IL指令的需求,得根据场景选择不同的解决方案:
场景1:动态生成IL(未完成编译)
如果正在用ILGenerator构建方法,直接通过标签定义和标记的方式绑定目标位置即可:
// 假设已有对应的ILGenerator实例 ILGenerator ilGen = ...; // 先定义目标标签 Label targetLabel = ilGen.DefineLabel(); // 在IL_0067对应的指令位置(ldc.i4.8之前)标记标签 ilGen.MarkLabel(targetLabel); ilGen.Emit(OpCodes.Ldc_I4_8); // 回到IL_004e的位置,替换原ldstr指令为跳转指令 ilGen.Emit(OpCodes.Br_S, targetLabel); // 用短跳转匹配原代码的ble.s格式,偏移量较长时可改用Br
场景2:修改已编译的程序集
如果是修改已存在的编译后程序集,推荐使用dnlib、Mono.Cecil这类专门的IL编辑库,它们直接处理IL偏移量,不需要依赖System.Reflection.Emit.Label。以Mono.Cecil为例:
var module = ModuleDefinition.ReadModule("yourAssembly.dll"); var targetType = module.Types.First(t => t.Name == "classname"); var targetMethod = targetType.Methods.First(m => ...); // 定位到目标方法 // 找到IL_004e对应的指令(偏移量0x4e) var instToReplace = targetMethod.Body.Instructions.First(inst => inst.Offset == 0x4e); // 找到IL_0067对应的指令(偏移量0x67)作为跳转目标 var targetInst = targetMethod.Body.Instructions.First(inst => inst.Offset == 0x67); // 替换指令为短跳转 instToReplace.OpCode = OpCodes.Br_S; instToReplace.Operand = targetInst; // 保存修改后的程序集 module.Write("modifiedAssembly.dll");
为什么不存在Label.FromString?
Label是ILGenerator在IL生成阶段维护的内部标记,它的有效性仅局限于当前正在构建的方法上下文。而IL偏移量(比如IL_0067)是IL生成完成后才确定的最终地址,两者没有直接的预映射关系,因此.NET原生框架不会提供从偏移量字符串创建Label的方法。
内容的提问来源于stack exchange,提问作者jmucchiello
相关产品推荐
相关产品推荐

