I looked at the IL code of a valid method with Reflector, and I came across this:
L_00a5: leave.s L_0103
Instructions with the suffix .s must take the operand int8, and, of course, this should also be the case with Leave_S , However, 0x0103 is 259, which exceeds the capacity of int8. The method somehow works, but when I read the instructions using the Mono.Reflection.Disassembler.GetInstructions method, it retrieves
L_00a5: leave.s L_0003
i.e. 3 instead of 259 because it must be int8. So my question is: how is the initial instruction possible ( leave.s L_0103 )? I looked at the ECMA documentation for this (section III: CIL instruction set) and I can not find anything that explains this.
Any ideas? Thanks.
EDIT # 1: Alright, I'm an idiot. In the case of branch instructions, the offset should be counted from the beginning of the instruction following the current instruction. I swear I read the documentation, but somehow I managed to miss it. In my defense today I am very sick. Sigh.
Thanks. (And thanks for not calling me an idiot, although that was pretty idiotic: P)
EDIT # 2: By the way, in case anyone is interested when Mono.Reflection.Disassembler.GetInstructions parses instructions, it changes the value of the operand in the branch instructions. In particular, as was indicated, the operand of the jump command represents the offset from the beginning of the next command, and not from 0. However, Mono.Reflection returns an offset starting at 0 (this may be why I was confused, although it does not explain how I managed skip part of the documentation).
Excerpt from MethodBodyReader.ReadOperand(Instruction instruction) :
switch (instruction.OpCode.OperandType) { ... case OperandType.ShortInlineBrTarget: instruction.Operand = (sbyte) (il.ReadByte () + il.position); break; ... }
As you can see, this adds il.position , which is the offset (starting at 0) of the next command. Also, it goes to sbyte , so I get 3 instead of 259. This seems like an error (an offset from 0 may be greater than sbyte ). I will ask Jb Evain (the author) and report back.
EDIT # 3: He hasn't answered yet, but I changed it to:
switch (instruction.OpCode.OperandType) { ... case OperandType.ShortInlineBrTarget: instruction.Operand = ((sbyte) il.ReadByte ()) + il.position; break; ... }
and it looks like he solved my problem. I passed sbyte to get the character to the right, in case it sbyte back (negative offset), and then when I add il.position (which is int ), the result is int .
I'll let you know what he says anyway.
EDIT # 4 : I forgot to report it. The author confirms that this was a mistake.