【发布时间】:2010-06-09 00:59:59
【问题描述】:
我正在使用 Reflector 查看有效方法的 IL 代码,但遇到了这样的情况:
L_00a5: leave.s L_0103
后缀为.s 的指令应该采用int8 操作数,当然this should be the case with Leave_S as well。但是0x0103是259,超出了一个int8的容量。该方法以某种方式有效,但是当我使用方法 Mono.Reflection.Disassembler.GetInstructions 阅读说明时,它会检索
L_00a5: leave.s L_0003
也就是说,3 而不是 259,因为它应该是 int8。所以,我的问题是:原始指令 (leave.s L_0103) 怎么可能?我查看了ECMA documentation for that(Partition III:CIL 指令集),但找不到任何解释。
有什么想法吗?谢谢。
编辑#1:好吧,我是个白痴。在分支指令的情况下,偏移量必须从当前指令之后的指令的开头开始计算。我发誓我阅读了文档,但不知何故我设法跳过了它。在我的辩护中,我今天病得很重。叹息。
谢谢。 (感谢你没有叫我白痴,尽管这很白痴:P)
编辑#2:顺便说一句,如果有人感兴趣,当Mono.Reflection.Disassembler.GetInstructions 反汇编指令时,它会改变分支指令中操作数的含义。特别是,正如已经指出的那样,分支指令的操作数表示从下一条指令开始的偏移量,而不是从 0。但是,Mono.Reflection 会返回从 0 开始的偏移量(这可能是我感到困惑的原因;虽然它没有解释我是如何设法跳过部分文档的)。
MethodBodyReader.ReadOperand(Instruction instruction) 的摘录:
switch (instruction.OpCode.OperandType) {
...
case OperandType.ShortInlineBrTarget:
instruction.Operand = (sbyte) (il.ReadByte () + il.position);
break;
...
}
如您所见,它添加了il.position,这是下一条指令的偏移量(从 0 开始)。此外,它转换为sbyte,这就是我得到3 而不是259 的原因。这似乎是一个错误(从0 开始的偏移量可能大于sbyte)。我会问 Jb Evain(作者)并报告。
编辑#3:他还没有回答,但我已将其更改为:
switch (instruction.OpCode.OperandType) {
...
case OperandType.ShortInlineBrTarget:
instruction.Operand = ((sbyte) il.ReadByte ()) + il.position;
break;
...
}
它似乎解决了我的问题。我投射到sbyte 以使符号正确,以防它是向后跳转(负偏移),然后当我添加il.position(这是一个int)时,结果是一个int。
无论如何,我会让你知道他说了什么。
编辑#4:我忘了报告。作者确认这是一个错误。
【问题讨论】:
-
为您辩护,根据过去使用小型微控制器(摩托罗拉 MC68HC11 有人吗?)的汇编语言和相关分支指令的经验,我在文档中搜索了“偏移”一词。如果没有先前的经验,很容易错过。顺便说一句,相对分支在 PC 上的可重定位代码中也是一个很大的好处,例如可以在不同内存地址加载的 DLL,因为动态加载器不必修复它们。当然,在 .NET 中涉及到 JIT,所以这种优化并不真正适用……它只是为了节省空间。
标签: c# .net reflection reflection.emit il