Вопрос

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

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

Это что-то столь же хакерское, как преобразование мнемонических инструкций в двоичные коды, помещение их в указатель 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();
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top