【发布时间】:2017-06-11 10:28:27
【问题描述】:
我一直想知道 V8 JavaScript 引擎和任何其他 JIT 编译器如何执行生成的代码。
这是我在尝试编写一个小演示时阅读的文章。
- 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);生成的程序集。