2017-02-09 23 views
2

Пусть говорят, что я хотел бы сделать вид JIT компиляции в C. Я разборку функцию и вставьте его код в памяти прямо в моей программе:Выполнение кода из памяти

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <sys/mman.h> 


void* alloc_executable_memory(size_t size) { 

    void *ptr = mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 

    if (ptr == MAP_FAILED) { 
     fprintf(stderr, "%s\n", "mmap failed"); 
     return NULL; 
    } 

    return ptr; 
} 

void push_code_into_memory(unsigned char *memory) { 
    unsigned char code[] = { 
    0x48, 0x89, 0xf8,  // mov %rdi, %rax 
    0,48, 0x83, 0xc0, 0x04, // add $4, %rax 
    0xc3     // ret 
    }; 

    memcpy(memory, code, sizeof(code)); 
} 

int make_memory_executable(void* memory, size_t size) { 

    if (mprotect(memory, size, PROT_READ | PROT_EXEC) == -1) { 
     fprintf(stderr, "%s\n", "mprotect failed"); 
     return -1; 
    } 
    return 0; 
} 

const size_t SIZE = 512; 
typedef long (*jitFunc)(long); 

int main(int argc, char const *argv[]) { 

    void *mem = alloc_executable_memory(SIZE); 
    push_code_into_memory((unsigned char *)mem); 
    make_memory_executable(mem, SIZE); 

    jitFunc foo = (jitFunc)mem; 
    int res = foo(2); 
    printf("%d\n", res); 

    return 0; 
} 

Однако, я всегда получаю выдаёт ошибку сегментации 11 (macOS) после вызова foo. Что не так с этим кодом? Во-первых, я думал, что проблема связана с правами доступа, но флаги, кажется, установлены правильно.

+1

отладчик может быть полезным здесь. –

+0

Кроме того, вы должны убедиться, что компилятор соблюдает соглашение о вызове, требуемое функцией jitted, то есть аргумент '2' должен находиться в' rdi', а не в стеке. –

+0

@BlagovestBuyukliev Да ... Я бы также сделал соглашения о вызовах явным, проверьте, действительно ли вы работаете на x64 (а не на x86), а затем реальные ужасы построения собственного JIT действительно начинаются ... Я построил несколько JIT в прошлом, но в настоящее время просто рекомендуют использовать LLVM. – atlaste

ответ

6

Думаю, что я нашел:

0,48, 0x83, 0xc0, 0x04 

должен быть

0x48, 0x83, 0xc0, 0x04 
+0

Спасибо большое, такая глупая ошибка, и много впустую time..Now это работает правильно – NikitaRock