2016-06-09 47 views
1

我測試了一個解釋器調度技術,被稱爲inline threading,我似乎無法轉入可執行內存沒有segfaulting。我使用GCC的labels as values擴展來確定每個操作碼範圍的開始和結束。內聯線程調度與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; 
} 

編譯和運行用:

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

我期待主返回2,而是:

Segmentation fault 
139 

我用mcc 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

對於x86_64和aarch64,使用GCC,I pinned a variable to a callee saved register來消除相對尋址和相對跳轉問題。在檢查生成的組件之後,我還重新構造了標籤,因爲引入了不希望的跳轉。因爲我已經用gcc版本4.8.4編譯它針對x86_64的-Linux的GNU和gcc版本6.1.0目標aarch64-Linux的Android和兩個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 

我會繼續尋找,不涉及一個變量到寄存器的明確的釘扎的解決方案。