Методы генерации JIT-кода - PullRequest
       19

Методы генерации JIT-кода

19 голосов
/ 05 сентября 2008

Как виртуальная машина генерирует машинный код на лету и выполняет его?

Предполагая, что вы можете выяснить, какие операционные коды машинной системы вы хотите выдать, как вы на самом деле выполняете ее?

Является ли это чем-то таким же хакерским, как отображение мнемонических инструкций в двоичные коды, вставка их в указатель char *, приведение их в виде функции и выполнение?

Или вы бы сгенерировали временную разделяемую библиотеку (.dll или .so или любую другую) и загрузили бы ее в память, используя стандартные функции, такие как LoadLibrary?

Ответы [ 7 ]

8 голосов
/ 05 сентября 2008

Вы можете просто заставить программный счетчик указывать на код, который вы хотите выполнить. Помните, что данные могут быть данными или кодом. На x86 счетчиком программ является регистр EIP. IP-часть EIP обозначает указатель инструкций. Инструкция JMP вызывается для перехода к адресу. После скачка EIP будет содержать этот адрес.

Это что-то столь же хакерское, как отображение мнемонических инструкций в двоичные коды, вставка их в указатель char *, приведение их в виде функции и выполнение?

Да. Это один из способов сделать это. Результирующий код будет приведен к указателю на функцию в C.

6 голосов
/ 16 сентября 2008

Является ли это чем-то таким же хакерским, как отображение мнемонических инструкций в двоичные коды, вставка их в указатель char *, приведение их в виде функции и выполнение?

Да, если бы вы делали это на C или C ++ (или что-то подобное), это именно то, что вы бы сделали.

Это кажется хакерским, но на самом деле это артефакт дизайна языка. Помните, что фактический алгоритм, который вы хотите использовать, очень прост: определите, какие инструкции вы хотите использовать, загрузите их в буфер в памяти и перейдите к началу этого буфера.

Если вы действительно пытаетесь сделать это, убедитесь, что вы правильно поняли соглашение о вызовах, когда вернетесь в свою C-программу. Я думаю, что если бы я хотел сгенерировать код, я бы искал библиотеку, которая позаботилась бы об этом для меня. Nanojit был в новостях недавно; Вы можете посмотреть на это.

4 голосов
/ 18 сентября 2008

Да. Вы просто создаете символ * и выполняете его. Тем не менее, вам нужно отметить пару деталей. Символ * должен находиться в исполняемом разделе памяти и иметь правильное выравнивание.

В дополнение к nanojit вы также можете проверить LLVM, которая является другой библиотекой, которая способна компилировать различные представления программ вплоть до указателя на функцию. Его интерфейс чистый, а сгенерированный код имеет тенденцию быть эффективным.

1 голос
/ 01 июля 2010

Это что-то хакерское, как отображение мнемонические инструкции к двоичному коды, вставляя их в символ * указатель и приведение его как функция и выполняется?

Да, это работает.

Чтобы сделать это в окнах, вы должны установить 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();
1 голос
/ 15 января 2009

О генерации DLL: дополнительный требуемый ввод-вывод для этого, плюс связывание, плюс сложность генерации формата DLL, значительно усложнит процесс, и, прежде всего, снизит производительность; Кроме того, в конце концов вы по-прежнему вызываете указатель функции на загруженный код, так что ... Кроме того, JIT-компиляция может выполняться по одному методу за раз, и если вы захотите это сделать, вы сгенерируете множество маленьких DLL.

Что касается требования "исполняемого раздела", вызов mprotect () в системах POSIX может исправить разрешения (аналогичный API есть в Win32). Это необходимо сделать для большого сегмента памяти, а не для каждого метода, так как в противном случае он будет слишком медленным.

На простой x86 вы не заметите проблему, на x86 с PAE или на 64-битных 64-битных машинах AMD64 / Intel вы получите ошибку.

1 голос
/ 16 сентября 2008

Как и Rotor 2.0, вы также можете взглянуть на виртуальную машину HotSpot в OpenJDK.

1 голос
/ 05 сентября 2008

Насколько я знаю, он компилирует все в памяти, потому что для оптимизации кода ему нужно запустить некоторую эвристику (т. Е. Вставку во времени), но вы можете взглянуть на общеязыковую инфраструктуру Shared Source 2.0 выпуск ротора. Вся кодовая база идентична .NET, за исключением джиттера и GC.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...