c - 我正在编写自己的 JIT 解释器。如何执行生成的指令?

标签 c assembly x86

我打算编写自己的 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/

相关文章:

c - 如何创建unix进程二叉树?

c - 分配 argv[i] = NULL

gcc - "gcc -x c"和 "gcc -x c++"汇编输出的区别

assembly - 相对跳转超出范围 0020h 字节

assembly - asm中的ADC指令

c++ - "rdtsc": "=a" (a0), "=d"(d0) 这是做什么的?

assembly - 在 x64 位处理器上编写 x86 程序集

将文件中的数字字符串转换为 C 中的 int 数组

c - gnu 链接器链接的文件的入口点地址是什么?

c - 如何在不显示 gdb 中的反斜杠转义的情况下打印带有换行符的空终止字符串?