c - 使用 memcpy 进行内联线程调度

标签 c inline interpreter mmap memcpy

我正在测试一种名为 inline threading 的解释器调度技术而且我似乎无法在没有段错误的情况下分支到可执行内存。我正在使用labels as values GCC 扩展以确定每个操作码范围的开始和结束。

测试.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 $?

我期望 main 返回 2,但相反:

Segmentation fault
139

我正在 64 位 Linux 机器上使用 gcc 4.7.2 进行编译,并且确信没有任何内容被优化。关于如何让它发挥作用有什么建议吗?

最佳答案

使用 GCC,我 pinned a variable to a callee saved register对于 x86_64 和 aarch64 来说,可以消除相对寻址和相对跳转问题。由于引入了不需要的跳转,在检查生成的程序集后,我还重组了标签。此后,我使用针对 x86_64-linux-gnu 的 gcc 版本 4.8.4 和针对 aarch64-linux-android 的 gcc 版本 6.1.0 编译了它,并且都产生了预期结果 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

我将继续寻找不涉及将变量显式固定到寄存器的解决方案。

关于c - 使用 memcpy 进行内联线程调度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37732283/

相关文章:

html - 覆盖 HTML 表格边框属性

c++ - 如果在头文件中定义函数,inline 关键字是否有意义?

c++ - 声明内联函数 noexcept 有意义吗?

c - 数组数据类型内存分配

c - 范围内的随机发生器

c++ - Brainfuck 解释器奇怪的输出

compiler-construction - 解释器和动态类型语言

PHP解释器/编译器

c - C中的 boolean 函数

c - 扫描整数数组