【发布时间】:2011-07-20 18:42:46
【问题描述】:
我正在尝试解析 IL 以发出一个方法。我在 string[] 中获得了一个方法的 IL 代码,其中每个字符串都是一条 IL 指令。我正在循环这个数组并使用 ILGenerator 添加操作码:
foreach (string ins in instructions) //string representations of IL
{
string opCode = ins.Split(':').ElementAt(1);
// other conditions omitted
if (opCode.Contains("br.s"))
{
Label targetInstruction = ilGenerator.DefineLabel();
ilGenerator.MarkLabel(targetInstruction);
ilGenerator.Emit(OpCodes.Br_S, targetInstruction);
}
这是我需要重现的 IL:
Source IL:
IL_0000: nop
IL_0001: ldstr "Hello, World!"
IL_0006: stloc.0
IL_0007: br.s IL_0009
IL_0009: ldloc.0
IL_000a: ret
这是我得到的输出:
Target IL:
IL_0000: nop
IL_0001: ldstr "Hello, World!"
IL_0006: stloc.0
IL_0007: br.s IL_0007 // this is wrong -- needs to point to IL_0009
IL_0009: ldloc.0
IL_000a: ret
如您所见, br.s 调用指向自身,这当然会导致无限循环。如何让它指向源代码中的以下指令?这与使用 Reflection.Emit.Label 有关,但我不确定它是如何工作的。
EDIT顺便说一下上面看到的IL就是针对这个简单的方法,
public string HelloWorld()
{
return "Hello, World!";
}
【问题讨论】:
-
这里肯定有什么我没看到的东西……为什么要跳转到下一条指令?这不只是一个稍微昂贵的无操作吗?另外,如果您不希望它成为目标,为什么要将分支指令标记为标签目标?
-
在 Emit() 调用之后移动 MarkLabel() 调用。或者只是完全省略分支,它什么都不做。
-
@Sean 我想你很快就会意识到你已经不知所措了。如果您计划实现一个完整的 IL 汇编器,那么对于分支指令,您将不得不比“string.Contains”做得更好。您基本上需要创建一个标签,并为它找到正确的位置。并非所有分支都“用于下一行”。
-
@Lasse,我知道,我只是湿了脚......
-
@Sean 然后 IL 是让他们湿透的好方法,并了解 .NET 程序的底层发生了什么:)
标签: c# reflection reflection.emit il opcode