Методы генерации JIT-кода
-
09-06-2019 - |
Вопрос
Как виртуальная машина на лету генерирует собственный машинный код и выполняет его?
Предположим, вы можете выяснить, какие машинные коды операций вы хотите сгенерировать, как вы на самом деле запустите их?
Это что-то столь же хакерское, как преобразование мнемонических инструкций в двоичные коды, помещение их в указатель char*, преобразование в функцию и выполнение?
Или вы бы создали временную общую библиотеку (.dll или .so или что-то еще) и загрузили ее в память, используя стандартные функции, такие как LoadLibrary
?
Решение
Вы можете просто сделать счетчик команд укажите код, который вы хотите выполнить.Помните, что данные могут быть данными или кодом.На x86 счетчиком программ является регистр EIP.IP-часть EIP означает указатель инструкций.Инструкция JMP вызывается для перехода по адресу.После перехода EIP будет содержать этот адрес.
Это что-то столь же хакерское, как преобразование мнемонических инструкций в двоичные коды, помещение их в указатель char*, преобразование в функцию и выполнение?
Да.Это один из способов сделать это.Результирующий код будет преобразован в указатель на функцию в С.
Другие советы
Это что-то столь же хакерское, как преобразование мнемонических инструкций в двоичные коды, помещение их в указатель char*, преобразование в функцию и выполнение?
Да, если бы вы делали это на C или C++ (или чем-то подобном), вы бы сделали именно это.
Это кажется хакерским, но на самом деле это артефакт языкового дизайна.Помните, что фактический алгоритм, который вы хотите использовать, очень прост:определите, какие инструкции вы хотите использовать, загрузите их в буфер в памяти и перейдите к началу этого буфера.
Однако если вы действительно попытаетесь это сделать, убедитесь, что вы правильно поняли соглашение о вызовах, когда вернетесь к программе на C.Я думаю, что если бы я хотел сгенерировать код, я бы поискал библиотеку, которая позаботится об этом за меня.Nanojit недавно был в новостях;вы могли бы посмотреть на это.
Ага.Вы просто создаете char* и выполняете его.Однако необходимо отметить пару деталей.Символ* должен находиться в исполняемом разделе памяти и иметь правильное выравнивание.
В дополнение к nanojit вы также можете проверить LLVM, еще одну библиотеку, способную компилировать различные представления программ до указателя на функцию.Его интерфейс понятен, а сгенерированный код имеет тенденцию быть эффективным.
Насколько я знаю, он компилирует все в памяти, потому что ему нужно выполнить некоторую эвристику для оптимизации кода (т.е.:встраивание с течением времени), но вы можете взглянуть на Общий исходный код Common Language Infrastructure 2.0 освобождение ротора.Вся кодовая база идентична .NET, за исключением Jitter и GC.
Помимо Ротора 2.0, вы также можете взглянуть на Виртуальная машина HotSpot в OpenJDK.
О создании DLL:дополнительные необходимые для этого операции ввода-вывода, а также связывание и сложность создания формата DLL значительно усложнят задачу и, прежде всего, снизят производительность;кроме того, в конце концов вы все равно вызываете указатель функции на загруженный код, так что...Кроме того, JIT-компиляция может выполняться по одному методу за раз, и если вы хотите это сделать, вам придется создать множество небольших DLL.
Что касается требования «исполняемого раздела», вызов mprotect() в системах POSIX может исправить разрешения (аналогичный API есть в Win32).Вместо этого вам нужно сделать это для большого сегмента памяти один раз для каждого метода, так как в противном случае это будет слишком медленно.
На обычном x86 вы не заметите проблему, на x86 с PAE или 64-битными компьютерами AMD64/Intel 64 бит вы получите ошибку сегмента.
Это что -то столь же хакерское, как отображение мнемонических инструкций с двоичными кодами, заполняя его в указатель чар* и подчиняя его в качестве функции и выполнения?
Да, это работает.
Чтобы сделать это в Windows, вы должны установить PAGE_EXECUTE_READWRITE для выделенного блока:
void (*MyFunc)() = (void (*)()) VirtualAlloc(NULL, sizeofblock, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
//Now fill up the block with executable code and issue-
MyFunc();