我正在使用 Reflector 查看有效方法的 IL 代码,我遇到了这个问题:
L_00a5: leave.s L_0103
带有后缀.s
的指令应该采用 int8 操作数,果然这也应该是 Leave_S 的情况。但是0x0103是259,超出了一个int8的容量。该方法以某种方式起作用,但是当我使用Mono.Reflection.Disassembler.GetInstructions
它检索的方法阅读说明时
L_00a5: leave.s L_0003
也就是说,3 而不是 259,因为它应该是 int8。所以,我的问题是:原始指令 ( leave.s L_0103
) 怎么可能?我已经查看了ECMA 文档(第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 开始的偏移量可能大于 a 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:我忘了报告。作者确认这是一个错误。