Я смотрел на код 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, может быть больше, чем 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: Я забыл сообщать. Автор подтверждает, что это было ошибкой.
целевая инструкция, представленная как 1-байтовое смещение со знаком от начала инструкции, следующей за текущей инструкцией
0xA5 находится в пределах 127 байтов от 0x103. Однако нет возможности для leave.s
перейти от 0xA5 до 0x03.