我打算编写自己的 JIT 解释器作为 VM 类(class)的一部分。我对高级语言、编译器和解释器有很多了解,但对 x86 汇编(或与此相关的 C)知之甚少或一无所知。
实际上我不知道 JIT 是如何工作的,但这是我的看法:用某种中间语言读入程序。将其编译为 x86 指令。确保最后一条指令返回到 VM 代码中正常的某个位置。将指令存储在内存中的某个位置。无条件跳转到第一条指令。瞧!
因此,考虑到这一点,我有以下小型 C 程序:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
int main() {
int *m = malloc(sizeof(int));
*m = 0x90; // NOP instruction code
asm("jmp *%0"
: /* outputs: */ /* none */
: /* inputs: */ "d" (m)
: /* clobbers: */ "eax");
return 42;
好的,所以我的目的是让这个程序将 NOP 指令存储在内存中的某个位置,跳转到那个位置,然后可能会崩溃(因为我没有设置任何方法让程序返回到主程序)。
问题:我走的路对吗?
问题:你能给我展示一个经过修改的程序,它设法找到返回 main 内部某处的路径吗?
问题:其他需要注意的事项?
PS:我的目标是获得理解,不一定以正确的方式做每件事。
感谢所有反馈。以下代码似乎是在我的 Linux 机器上开始和工作的地方:
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/mman.h>
unsigned char *m;
int main() {
unsigned int pagesize = getpagesize();
printf("pagesize: %u\n", pagesize);
m = malloc(1023+pagesize+1);
if(m==NULL) return(1);
printf("%p\n", m);
m = (unsigned char *)(((long)m + pagesize-1) & ~(pagesize-1));
printf("%p\n", m);
if(mprotect(m, 1024, PROT_READ|PROT_EXEC|PROT_WRITE)) {
printf("mprotect fail...\n");
return 0;
}
m[0] = 0xc9; //leave
m[1] = 0xc3; //ret
m[2] = 0x90; //nop
printf("%p\n", m);
asm("jmp *%0"
: /* outputs: */ /* none */
: /* inputs: */ "d" (m)
: /* clobbers: */ "ebx");
return 21;
}
最佳答案
Question: Am I on the right path?
我会说是的。
Question: Could you show me a modified program that manages to find its way back to somewhere inside main?
我没有任何代码给你,但是获取生成的代码并返回的更好方法是使用一对 call
/ret
指令,因为他们会自动管理回邮地址。
Question: Other issues I should beware of?
是的——作为一种安全措施,许多操作系统会阻止您在堆上执行代码而不做特殊安排。这些特殊安排通常意味着您必须将相关内存页标记为可执行文件。
在 Linux 上,这是使用 mprotect()
完成的使用 PROT_EXEC
。
关于c - 我正在编写自己的 JIT 解释器。如何执行生成的指令?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9015541/