2016-06-09 14 views
1

Я тестирую методику отправки интерпретатора, называемую inline threading, и я не могу попасть в исполняемую память без segfault. Я использую расширение GCC labels as values для определения начала и конца каждого интервала кода операции.Inline threaded dispatch with memcpy

test.c:

#include <string.h> 
#include <unistd.h> 
#include <sys/mman.h> 

int main (int argc, char** argv) { 

    int i = 0; 

    if (argc > 0x10) { 
    // prevent optimization 
    inc_start: i++; inc_end:; 
    ret_start: goto end; ret_end:; 
    } 

    void* m = mmap(
    0, 
    getpagesize(), 
    PROT_WRITE | PROT_EXEC, 
    MAP_ANONYMOUS | MAP_PRIVATE, 
    -1, 
    0); 

    if (!m) { 
    return -1; 
    } 

    { 
    char* x = m; 
    memcpy(x, &&inc_start, &&inc_end - &&inc_start); x += &&inc_end - &&inc_start; 
    memcpy(x, &&inc_start, &&inc_end - &&inc_start); x += &&inc_end - &&inc_start; 
    memcpy(x, &&ret_start, &&ret_end - &&ret_start); x += &&ret_end - &&ret_start; 
    } 

    goto *m; 

    end: 
    return i; 
} 

Compile и работать с:

gcc test.c -O0 && ./a.out; echo $? 

Я ожидаю главный вернуться 2, но вместо этого:

Segmentation fault 
139 

I компиляция с gcc 4.7.2 на 64-битная Linux-машина, и я уверен, что ничто не оптимизируется. Любые советы о том, как это сделать?

+0

Код Youir не является стандартным C и вызывает неопределенное поведение. Какой у Вас вопрос? – Olaf

+0

Вы ссылались на ярлыки как на ссылку значений? Да, это не стандарт, но расширение поддерживается большинством компиляторов C. Как автор этой статьи получил встроенную поточную диспетчерскую работу? http://www.sable.mcgill.ca/publications/papers/2003-2/sable-paper-2003-2.pdf См. рисунок 2. – ytrp

+0

Я не буду, потому что это неправильный подход и не допускается веские причины. Я не здесь, чтобы учиться, просто сказал вам. (И нет, это не поддерживается ** большинством ** компиляторов! Есть больше, чем gcc, msvc и clang/llvm. – Olaf

ответ

1

Использование GCC, I pinned a variable to a callee saved register для x86_64 и aarch64 для устранения относительной адресации и относительной ошибки перехода. Я также изменил этикетки после изучения сгенерированной сборки, поскольку вводились нежелательные скачки. Я с тех пор он был скомпилирован с GCC версии 4.8.4 нацеливание x86_64-Linux-гну и GCC версии 6.1.0 таргетирования aarch64-линукс-андроида, и оба получают предполагаемый результат 2.

// gcc test.c -O3 && ./a.out; echo $? 
#include <string.h> 
#include <unistd.h> 
#include <sys/mman.h> 

#if defined(__amd64__) || defined(__x86_64__) 
register long i asm ("r15"); 
#elif defined(__arch64__) 
register long i asm ("x16"); 
#else 
#error Unsupported architecture. Supported: x86_64, aarch64 
#endif 
long main (int argc, char** argv) { 
    i = 0; 

    void* m = mmap(0, getpagesize(), 
       PROT_WRITE | PROT_EXEC, 
       MAP_ANONYMOUS | MAP_PRIVATE, 
       -1, 0); 

    if (!m) { 
    return -1; 
    } 

    { 
    char* x = m; 
    memcpy(x, &&L00, &&L01 - &&L00); x += &&L01 - &&L00; // inc 
    memcpy(x, &&L00, &&L01 - &&L00); x += &&L01 - &&L00; // inc 
    memcpy(x, &&L01, &&L02 - &&L01); x += &&L02 - &&L01; // ret 
    } 

    goto *m; 

    L00: i++;  // inc 
    L01: return i; // ret 
    L02:; 

    return -2; 
} 

компилировать и запускать с:

gcc test.c -O3 && ./a.out; echo $? 
2 

Я буду продолжать искать решение, которое не предполагает явного пиннинга переменной в регистр.

 Смежные вопросы

  • Нет связанных вопросов^_^