Пишу собственный JIT-интерпретатор. Как мне выполнять сгенерированные инструкции?

Я собираюсь написать свой собственный JIT-интерпретатор как часть курса по виртуальным машинам. Я у меня много знаний о языках высокого уровня, компиляторах и интерпретаторах, но мало или совсем нет знаний о сборке x86 (или C, если на то пошло).

На самом деле я не знаю, как работает JIT, но вот мое мнение на нем: Прочтите программу на каком-то промежуточном языке. Скомпилируйте ее в инструкции x86. Убедитесь, что последняя инструкция вернулась куда-нибудь в разумное место обратно в код виртуальной машины. Сохраните инструкции где-нибудь в памяти. Выполните безусловный переход к первой инструкции. Вуаля !

Имея это в виду, у меня есть следующая небольшая программа на 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;
}
7
задан Magnus Madsen 8 February 2012 в 09:42
поделиться