[ASM] С какой инструкции началась загрузка данных в стек до вызова метода?

Версия Minecraft
1.7.10
API
Forge
236
4
22
Добрый день всем. Вообщем, нужна помощь с ASM`ом. Мне иногда нужно полностью удалить вызов X метода (INVOKE_...) из метода, который я "исправляю". Чтобы это сделать, мне нужно узнать с какой инструкции началась загрузка данных в стек до вызова этого метода, дабы эти инструкции также стереть, иначе будут ошибки, что логично. Есть и похожие случаи, когда мне нужно обернуть вызов метода X в IF [if(...) {вызов метода;}], где опять же нужно знать с какой инструкции началась загрузка в стек, дабы их тоже обернуть в этот же IF. Есть ли уже встроенные методы-утилиты для поиска инструкций загрузки данных в стек при инвоке метода в самой ASM либе, или же только самому делать велосипед? Просто если самому такое пытаться сделать, уверен, что или крашнется сразу или будет работать "на соплях", ибо так просто явно не найти эти инструкции (Я предполагаю это нужно посчитать сколько аргументов требуется для вызова метода, а затем в обратном порядке искать инструкции, которые загружают эти данные из стека. Но ведь инструкции загрузки может и не быть, а будет лишь метод, который возвращает значение, а при вызове этого метода могут быть ещё нужны какие-либо параметры - как тогда посчитать что относится к "целевой загрузке" данных в стек, а что к "подцелевой" загрузке для вызова субметодов?... Возможно тут в помощь рекурсия, но я не на сколько сейчас эксперт в java байткоде, чтобы осилить такое, ибо я вообще дебил.)

Если кому интересно зачем мне этот бред - всё просто. Все мы знаем, что сейчас есть ни 1 и не 2 ядра для серверов, и каждое ядро по своему патчит методы (через -Dlegacy.debugClassLoading=true -Dlegacy.debugClassLoadingSave=true я в термос ядре находил и вовсе не схожие с оригинальным кодом майнкрафта классы), а значит я не могу просто "посчитать" сколько там инструкций вызвалось до вызова нужного мне метода и эти инструкции циклом удалить, ибо тогда просто крашнутся эти ядра - нужен более надёжный способ, который соберёт инструкции, "привязанные" к инвоку метода. ( Я кнш понимаю, что ASM вещь такая, что на свой страх и риск, но без неё некоторые вещи не выполнимы даже через хуклибы, и хочется чтоб то что делаешь хоть как-то имело поддержку большинство ядер )
 
1,074
72
372
Я предполагаю это нужно посчитать сколько аргументов требуется для вызова метода, а затем в обратном порядке искать инструкции, которые загружают эти данные из стека.
Именно так. Найти нужный метод, сделать несколько шагов назад и удалить. Если метод и код заранее известны, можно захардкодить кол-во удаляемых элементов. Вариант попроще и не самый красивый: удалить помещённые значения инструкциями POP.

я в термос ядре находил и вовсе не схожие с оригинальным кодом майнкрафта классы), а значит я не могу просто "посчитать" сколько там инструкций вызвалось до вызова нужного мне метода
В ваш трансформер приходит массив байт. Сохраните его в файл, потом смотрите в декомпиляторе что там приходит. Есть декомпиляторы, которые умеют показывать байт-код.
 
154
17
97
Слушай, твой АСМ был резонен в использовании, когда тебе приходилось патчить множество классов одновременно небольшой логикой. Если ты пишешь не публичный мод (хотя в паблике тебя бы и так задушили за такое объемное использование ASM), я настоятельно рекомендую тебе посмотреть на миксины, а в особенности Grimoire для 1.7.10. Пример юзания и гайд по настройке есть в соседней репе.
И если уж заговорили про Термос, то вот тебе еще его обновляющийся и пофикшеный наследник.
Менять вещи, привязанные к вызову определенного метода, по хорошему стоит только миксинами.
Например, твои две задачи по отмене вызова метода или обертке его в IF можно решить простейшим Redirect’ом
 
Последнее редактирование:
236
4
22
Именно так. Найти нужный метод, сделать несколько шагов назад и удалить. Если метод и код заранее известны, можно захардкодить кол-во удаляемых элементов. Вариант попроще и не самый красивый: удалить помещённые значения инструкциями POP.
Про поп вариант интересный, посмотрю.
В ваш трансформер приходит массив байт. Сохраните его в файл, потом смотрите в декомпиляторе что там приходит. Есть декомпиляторы, которые умеют показывать байт-код.
Я же почтим таким способом и пользуюсь. -Dlegacy.debugClassLoading=true -Dlegacy.debugClassLoadingSave=true в аргументах запуска заставляет Forge сохранять class`ы с байткодом после всех трансформеров из сборки, в которой был загружен сервер.
По desc вызываемого метода можно узнать количество аргументов, которые в него передаются.
Это я знаю, посчитать сколько и каких типов данных аргументы - легко. И как я понял этого в ASM нет, нужно самому делать.
 
83
5
62
По факту самый надёжный и безопасный способ "удалить" вызов метода - это либо миксины и @Redirect, либо функциональный аналог редиректа на ASM. Смысл в том, что вместо того, чтобы трогать стек, ты берёшь все передаваемые в целевой метод аргументы (+объект, на котором этот метод вызывывается, если конечно он нужен), и заменяешь вызов целового метода вызовом какого-нибудь своего, внешнего, который всё это впитывает и возвращает тот же тип, что и целевой. А там уже в своём внешнем методе можно реализовывать любую дополнительную логику, или просто не реализовывать ничего, если задача просто подавить оригинальный вызов.
 
236
4
22
По факту самый надёжный и безопасный способ "удалить" вызов метода - это либо миксины и @Redirect, либо функциональный аналог редиректа на ASM. Смысл в том, что вместо того, чтобы трогать стек, ты берёшь все передаваемые в целевой метод аргументы (+объект, на котором этот метод вызывывается, если конечно он нужен), и заменяешь вызов целового метода вызовом какого-нибудь своего, внешнего, который всё это впитывает и возвращает тот же тип, что и целевой. А там уже в своём внешнем методе можно реализовывать любую дополнительную логику, или просто не реализовывать ничего, если задача просто подавить оригинальный вызов.
Именно так и сделал уже. "Догрузил" через *LOAD`ы ссылку на объект метода + параметры из метода в стек и заменить инвок метода на инвок своего статика, где "исправил" логику, добавив проверки. Тут проблема бывает лишь 1, когда нужно будет внешне обратиться к приватному/защищённому методу, который добавлен FML, ибо их не берёт AT. Тут уже только "обмануть IDEA, подложив свой класс из майнкрафта с паблик методом + в трансформере сменить модификатор доступа к методу, который нужно будет дернуть.
 
Сверху