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
つまり、int8 であるはずなので、259 ではなく 3 です。それで、私の質問: 元の指示 ( leave.s L_0103
) はどのように可能ですか? そのための ECMA ドキュメント( Partition III: CIL Instruction Set ) を見ましたが、それを説明するものが見つかりません。
何か案は?ありがとう。
編集#1:わかりました、私はばかです。分岐命令の場合、オフセットは現在の命令に続く命令の先頭からカウントする必要があります。ドキュメントを読んだことを誓いますが、どういうわけかそれをスキップすることができました。断言しますが、今日はかなり具合が悪いです。はぁ。
ありがとうございました。(そして、これはかなりばかげていたにもかかわらず、私をばかと呼ばないでくれてありがとう:P)
編集#2:ちなみに、誰かが興味を持っている場合Mono.Reflection.Disassembler.GetInstructions
、命令を逆アセンブルすると、分岐命令のオペランドの意味が変わります。特に、指摘されているように、分岐命令のオペランドは、 0 からではなく、次の命令の先頭からのオフセットを表します。しかし、0 からMono.Reflection
始まるオフセットを返します (これが、私が混乱した理由かもしれませんが、ドキュメントの一部をスキップした方法については説明していません)。
の抜粋MethodBodyReader.ReadOperand(Instruction instruction)
:
switch (instruction.OpCode.OperandType) {
...
case OperandType.ShortInlineBrTarget:
instruction.Operand = (sbyte) (il.ReadByte () + il.position);
break;
...
}
ご覧のとおりil.position
、次の命令のオフセット (0 から始まる) を追加します。また、それは にキャストされsbyte
ます。これが、259 ではなく 3 を取得している理由です。これはバグのようです (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 : 報告するのを忘れていました。作者はこれがバグであることを認めています。