Мне было интересно, как V8 JavaScript Engine и любые другие компиляторы JIT выполняют сгенерированный код.Как написать машинный код x64 в виртуальную память и выполнить его для Windows в C++
Вот статьи, которые я прочитал во время своей попытки написать небольшую демонстрационную версию.
- http://eli.thegreenplace.net/2013/11/05/how-to-jit-an-introduction
- http://nullprogram.com/blog/2015/03/19/
Я только знаю очень мало о сборке, поэтому я изначально использовал http://gcc.godbolt.org/ написать функцию и получить разобранном выход, но код не работает на Windows.
Затем я написал небольшой код на C++, скомпилированный с -g -Og
, а затем получите вывод данных с помощью gdb.
#include <stdio.h>
int square(int num) {
return num * num;
}
int main() {
printf("%d\n", square(10));
return 0;
}
Выход:
Dump of assembler code for function square(int):
=> 0x00000000004015b0 <+0>: imul %ecx,%ecx
0x00000000004015b3 <+3>: mov %ecx,%eax
0x00000000004015b5 <+5>: retq
копировать-вставить выход ('%' удалены) для online x86 assembler и получить { 0x0F, 0xAF, 0xC9, 0x89, 0xC1, 0xC3 }
.
Вот мой последний код. если я скомпилировал его с gcc, я всегда получаю 1. Если я скомпилировал его с VC++, я получаю случайное число. Что происходит?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <windows.h>
typedef unsigned char byte;
typedef int (*int0_int)(int);
const byte square_code[] = {
0x0f, 0xaf, 0xc9,
0x89, 0xc1,
0xc3
};
int main() {
byte* buf = reinterpret_cast<byte*>(VirtualAlloc(0, 1 << 8, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE));
if (buf == nullptr) return 0;
memcpy(buf, square_code, sizeof(square_code));
{
DWORD old;
VirtualProtect(buf, 1 << 8, PAGE_EXECUTE_READ, &old);
}
int0_int square = reinterpret_cast<int0_int>(buf);
int ans = square(100);
printf("%d\n", ans);
VirtualFree(buf, 0, MEM_RELEASE);
return 0;
}
Примечание
Я пытаюсь узнать, как JIT работает, поэтому, пожалуйста, не предложить мне использовать LLVM или любую библиотеку. Я обещаю, что буду использовать надлежащую библиотеку JIT в реальном проекте, а не писать с нуля.
Хороший вопрос, редактировал название, как было предложено. Я хочу, чтобы мой вопрос был полезным для других читателей, так как большинство статей JIT, которые я могу найти, предназначены для POSIX. –
Обратите внимание, что это не «в память кучи», вы выделяете страницу вне любой кучи (что лучше всего, так что ваш вызов «VirtualProtect» не влияет на какие-либо другие объекты) –
Показать сборку, сгенерированную для 'int ans = square (100); 'где вызывается указатель функции. –