Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/125.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何动态生成和运行本机代码?_C++_Linux_Compiler Construction_X86_Jit - Fatal编程技术网

C++ 如何动态生成和运行本机代码?

C++ 如何动态生成和运行本机代码?,c++,linux,compiler-construction,x86,jit,C++,Linux,Compiler Construction,X86,Jit,我想为我编写的玩具语言处理器(纯学术性)编写一个非常小的概念验证JIT编译器,但我在设计的中间阶段遇到了一些麻烦。从概念上讲,我熟悉JIT的工作原理——将字节码编译成(机器或程序集?)代码来运行。然而,在螺母和螺栓的层面上,我不太清楚你实际上是如何做到这一点的 我(非常“新手”)的下意识反应是,因为我不知道从哪里开始,我会尝试下面的方法: mmap()内存块,设置对PROT_EXEC的访问 将本机代码写入块中 将当前寄存器(堆栈指针等)存储在舒适的地方 修改当前寄存器以指向映射区域中的本机代码块

我想为我编写的玩具语言处理器(纯学术性)编写一个非常小的概念验证JIT编译器,但我在设计的中间阶段遇到了一些麻烦。从概念上讲,我熟悉JIT的工作原理——将字节码编译成(机器或程序集?)代码来运行。然而,在螺母和螺栓的层面上,我不太清楚你实际上是如何做到这一点的

我(非常“新手”)的下意识反应是,因为我不知道从哪里开始,我会尝试下面的方法:

  • mmap()内存块,设置对PROT_EXEC的访问
  • 将本机代码写入块中
  • 将当前寄存器(堆栈指针等)存储在舒适的地方
  • 修改当前寄存器以指向映射区域中的本机代码块
  • 本机代码现在将由计算机执行
  • 恢复以前的寄存器

  • 这是否接近正确的算法?我试过阅读我知道有JIT编译器要研究的不同项目(例如),但这些代码库由于其大小而很难使用,我不知道从哪里开始寻找。

    Android Dalvik JIT编译器可能也值得一看。它应该是相当小和精益的(不确定这是否有助于理解它或使事情更加复杂)。它也针对Linux

    如果事情变得越来越严重,那么查看LLVM也可能是一个不错的选择


    Jeremiah建议的函数指针方法听起来不错。您可能希望使用调用方的堆栈,并且可能只剩下少数寄存器(在x86上)需要保留或不接触。在这种情况下,如果编译后的代码(或条目存根)在继续之前将它们保存在堆栈上,这可能是最简单的。最后,这一切归结为编写汇编函数并从C与之接口。

    不确定linux,但这在x86/windows上是可行的。
    更新:

    #包括
    #包括
    typedef无符号字符字节;
    int arg1;
    int-arg2;
    int res1;
    类型定义无效(*pfunc)(无效);
    联合函数{
    pfunc-x;
    字节*y;
    };
    内部主(空){
    
    byte*buf=(byte*)VirtualAllocEx(GetCurrentProcess(),0,1您可能想看看libjit,它正好提供了您想要的基础结构:

    libjit库实现了 即时编译 与其他JIT不同,此 一个是设计成独立于 任何特定的虚拟机 字节码格式或语言


    除了目前建议的技术外,还值得研究线程创建功能。如果您创建了一个新线程,并将起始地址设置为生成的代码,您肯定知道没有需要保存或还原的旧寄存器,并且操作系统会为您处理相关寄存器的设置u、 例如,您删除了列表中的步骤3、4和6。

    您可能对的编程语言感兴趣。这是一种小型、不完整的语言,具有即时编译功能。Potion的小型使其更易于理解。存储库中包含对(JIT内容从标题“~JIT~”开始)的描述


    由于它是在的上下文中运行的,所以实现很复杂。不过,不要让这件事吓跑你。很快就会知道他在干什么。基本上,使用一小组VM操作码可以将一些操作建模为。答案取决于你的编译器和你把代码放在哪里。请参阅


    在32位Vista中,VisualC++提供了DEP(数据执行防止)错误,无论代码是否放在堆栈、堆或静态内存上。G++、Borland和Mars有时都可以工作。JIT代码访问的数据需要声明为易失性。

    是一篇新文章(从今天开始!)这解决了其中一些问题,也描述了更大的情况。

    您可能可以进一步简化:您通常可以在
    mmap
    “ed块中获取代码的起始地址,并将其强制转换为函数指针。在这种情况下,代码需要保存和恢复自己的寄存器等。您可以想要查看平台ABI(应用程序二进制接口)中的调用约定,以了解需要保存的内容(以及如何从C代码获取参数、调用C函数等)@Jeremiah Willcock:在我看来,这大概就是下面@Shelwien演示的技术,对吗?mmap到PROT_EXEC可能不起作用。我认为当前版本的Linux不允许任何内存同时具有可写性和可执行性。你需要将其映射为可写、可写,然后映射为可执行。或者我认为是这样。事实上,到目前为止,它在我的实验中似乎工作得很好。我使用的是最新的内核版本(2.6.35),并使用
    PROT_READ | PROT_WRITE | PROT_EXEC
    设置我的
    mmap()
    访问权限,这并不是因为你针对的是非x86,而是要注意那些自我修改的代码(或动态生成的代码)在其他平台上需要显式缓存同步。它几乎只有x86可以透明地进行同步(这意味着硅负载)。只需调用msync()Shelwien:它以前绝对不可移植,因为大多数现代操作系统都不接受堆栈的执行。感谢这个伟大的例子!我几乎没有意识到
    funcptr
    最初是一个
    联合体,之后它就有了完美的意义SED是一个简单的类型,比如((pFunc)(Vult*)BUF)();但是CODEAD说了一些关于ISO C++的不允许将随机的东西随机转换成函数,所以我必须用一个联合来替换它。需要在x64上工作?我不是组装专家,但我看不到任何x64不能反向兼容的东西。我的意思是
    
    #include <stdio.h>
    #include <windows.h>
    
    typedef unsigned char byte;
    
    int arg1;
    int arg2;
    int res1;
    
    typedef void (*pfunc)(void);
    
    union funcptr {
      pfunc x;
      byte* y;
    };
    
    int main( void ) {
    
      byte* buf = (byte*)VirtualAllocEx( GetCurrentProcess(), 0, 1<<16, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
    
      if( buf==0 ) return 0;
    
      byte* p = buf;
    
      *p++ = 0x50; // push eax
      *p++ = 0x52; // push edx
    
      *p++ = 0xA1; // mov eax, [arg2]
      (int*&)p[0] = &arg2; p+=sizeof(int*);
    
      *p++ = 0x92; // xchg edx,eax
    
      *p++ = 0xA1; // mov eax, [arg1]
      (int*&)p[0] = &arg1; p+=sizeof(int*);
    
      *p++ = 0xF7; *p++ = 0xEA; // imul edx
    
      *p++ = 0xA3; // mov [res1],eax
      (int*&)p[0] = &res1; p+=sizeof(int*);
    
      *p++ = 0x5A; // pop edx
      *p++ = 0x58; // pop eax
      *p++ = 0xC3; // ret
    
      funcptr func;
      func.y = buf;
    
      arg1 = 123; arg2 = 321; res1 = 0;
    
      func.x(); // call generated code
    
      printf( "arg1=%i arg2=%i arg1*arg2=%i func(arg1,arg2)=%i\n", arg1,arg2,arg1*arg2,res1 );
    
    }