2016-06-09 11 views
1

나는 inline threading이라고하는 인터프리터 디스패치 기술을 테스트 중이므로 segfaulting없이 실행 메모리로 분기 할 수없는 것처럼 보입니다. GCC의 labels as values 확장을 사용하여 각 opcode 범위의 시작과 끝을 결정합니다.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; 
} 

컴파일 및 실행 : 나는 2를 반환하는 주요 기대하고

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

, 대신 :

Segmentation fault 
139 

I gcc 4.7.2에서 컴파일하기 64 비트 리눅스 머신이며, 최적화 된 것이 아무것도 없다고 확신합니다. 이 작업을 수행하는 방법에 대한 정보는 무엇입니까?

+0

Youir 코드는 표준 C가 아니며 정의되지 않은 동작을 호출합니다. 귀하의 질문은 무엇인가? – Olaf

+0

레이블을 값 링크라고 부릅니까? 그렇습니다. 표준이 아니지만 확장은 대부분의 C 컴파일러에서 지원됩니다. 이 백서의 저자는 인라인 스레드 파견 작업을 어떻게 받습니까? http://www.sable.mcgill.ca/publications/papers/2003-2/safe-paper-2003-2.pdf 그림 2를 참조하십시오. – ytrp

+0

잘못된 접근법이며 허용되지 않기 때문에 제가 원하지 않습니다. 좋은 이유. 나는 여기 교사가 아니에요, 그냥 당신에게 말 했어요. (그리고 아니, 그것은 ** 대부분의 ** 컴파일러에 의해 지원되지 않는다! gcc, msvc, clang/llvm 이상이있다. – Olaf

답변

1

상대 주소 지정 및 상대 점프 문제를 제거하기 위해 GCC를 사용하여 x86_64 및 aarch64 모두에 대해 I pinned a variable to a callee saved register을 사용합니다. 또한 원치 않는 점프가 도입 되었기 때문에 생성 된 어셈블리를 검토 한 후 레이블을 재구성했습니다. 나는 이후 aarch64 - 리눅스 - 안드로이드 대상 x86_64에-리눅스 GNU와 GCC 버전 6.1.0을 대상으로 GCC 버전 4.8.4로 컴파일 한, 둘 다 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 

나는 레지스터에 변수를 명시 적으로 고정 기능을 포함하지 않는 솔루션을 검색 할 것입니다.