Я искал код IL действительного метода с Reflector, и я столкнулся с этим:
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)
EDIT # 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 : Я забыл сообщить. Автор подтверждает, что это была ошибка.