Инструментарий Dalvik bytecode - объединение типов регистров - PullRequest
0 голосов
/ 22 мая 2019

Я делаю что-то вроде байт-кода dalvik, используя dexlib2. Тем не менее, есть пара оставшихся вопросов. Слияние типов регистров, которое происходит после инструкций goto и ловить блоки, точнее по соответствующей метке, как-то получает неожиданный тип регистра, который в свою очередь нарушает инструментальный код.

Вставляемые инструкции выглядят следующим образом:

move(-wide,-object,/16,/from16) vNew, v0
const-string v0, "some string"
invoke-static, {v0}, LPathToSomeClass;->SomeMethod(Ljava/lang/String;)V
move(..) v0, vNew

Итак, v0 используется для хранения некоторого параметра для статического вызова функции, тогда как vNew - это новый (локальный) регистр для хранения и восстановления исходного содержимого v0. Тип регистра v0 выводится заранее, чтобы получить право инструкция перемещения, то есть перемещение по ширине, перемещение или перемещение объекта. Однако, когда этот код включен в некоторый блок try, инструментарий ломается. Выход из baksmali (baksmali d -b "" --register-info ALL, FULLMERGE --offsets) показывает, что тип v0 после инструкции const-string (то есть Reference, L / java / lang / String) рассматривается в качестве входных данных для процедуры слияния, происходящей, например, в соответствующей метке блока catch. Предполагая, что тип перед вставленным кодом был Reference, [I (int array) результирующий тип теперь Reference, L / java / lang / Object (который выдает ошибку проверки), хотя последняя команда перемещения восстанавливает исходный тип регистра.

Теперь на мои вопросы:

1) Когда на самом деле происходит это слияние?

2) Почему процедура слияния учитывает тип v0 после инструкции const-string? Учитывает ли каждая инструкция изменение типа любого регистра?

3) Эта проблема связана только с блоками try-catch?

4) Каковы ограничения для блоков try-catch в этом вопросе?

5) Есть ли какое-либо решение этой проблемы, кроме создания собственного метода для каждого кода, который нужно внедрить без параметров? Так можно ли использовать дополнительный регистр для решения этой проблемы?

6) Могу ли я обнаружить с помощью блоков try-catch dexlib2 и определить набор инструкций, которые они включают?

7) Есть ли какие-либо заметки / литература, обсуждающая эту проблему, например, процедура слияния и связанные с ней технические особенности, например, дальнейшие ограничения / ограничения для приборов?

Я высоко ценю любую помощь в этом вопросе. Заранее спасибо!

1 Ответ

0 голосов
/ 22 мая 2019

При объединении регистров в начале блока перехвата есть входящий фронт от каждой инструкции в блоке try, который может генерировать.Только определенные инструкции могут выдавать - как определено флагом опкода CAN_THROW .

В вашем конкретном примере, команда invoke-static после инструкции const-string может выдать, и поэтому есть реброот непосредственно перед этой инструкцией до начала блока catch.

Если вы сделаете шаг назад, выполнение может перейти от любой инструкции в блоке try, которая может переброситься к началу блока catch.И поэтому код в блоке catch должен быть подготовлен для того, чтобы регистры находились в состоянии, которое согласуется с содержимым регистра непосредственно перед любой из тех инструкций, которые могут выдавать.

Так, например, если естьодин возможный «переход» из блока try в блок catch, где регистр содержит примитивный тип int, и другой возможный переход, где он содержит объект, этот регистр считается «конфликтующим», поскольку регистр может содержать любой тип при этомуказать в коде, и эти два типа не совместимы друг с другом.Например, примитивный тип int никогда не может быть передан чему-то, ожидающему ссылочный тип, и наоборот.И в байт-коде нет механизма для статической проверки типов регистров.

Одним из возможных решений может быть разделение блока try в точке, где вы вставляете свои инструменты, так, чтобы само оборудование не охватывалось блоком try, но обе "стороны" оригинального кода есть.И имейте в виду, что в байт-коде один и тот же блок catch может использоваться несколькими блоками try, поэтому вы можете разделить исходный блок try на два, и оба будут ссылаться на исходный блок catch.

В противном случае выВам просто нужно будет найти какой-то способ надлежащим образом управлять регистрами, чтобы избежать этой проблемы.

Что касается 6), см. MethodImplementation.getTryBlocks () , который даст вам списокпопробуйте блоки в этом методе.Каждый блок try указывает, где он начинается, сколько инструкций он охватывает и все связанные с ним блоки catch (разные блоки catch для разных исключений).

...