直接执行数据

时间:2013-02-06 16:17:44

标签: c++

使程序执行数据的最佳方法是什么。说,我为 x86_64 机器编写了(所谓的)编译器:

#include <iostream>
#include <vector>

#include <cstdlib>
#include <cstdint>

struct compiler
{

    void op() const { return; }

    template< typename ...ARGS >
    void op(std::uint8_t const _opcode, ARGS && ..._tail)
    {
        code_.push_back(_opcode);
        return op(std::forward< ARGS >(_tail)...);
    }

    void clear() { code_.clear(); }

    long double operator () () const
    {
        // ?
    }

private :

    std::vector< std::uint8_t > code_;

};

int main()
{
    compiler compiler_; // long double (*)();
    compiler_.op(0xD9, 0xEE); // FLDZ
    compiler_.op(0xC3);       // ret
    std::cout << compiler_() << std::endl;
    return EXIT_SUCCESS;
}

但我不知道如何正确实施operator ()。我怀疑,我必须将code_的所有内容放入连续的内存块中,然后转换为long double (*)();并调用它。但是有一些困难:

  • 我应该在Windows上使用VirtualProtect(Ex)(+ FlushInstructionCache)吗?在Linux上类似的东西?
  • 什么是容器,可以以适当的方式(即逐个)将字节可靠地放入存储器中?并且还允许获取指向内存块的指针。

1 个答案:

答案 0 :(得分:2)

首先,您需要将代码分配为可执行文件[在Windows中使用带有“可执行”标志的VirtualAlloc,并使用“MAP_EXECUTABLE”作为标志之一]使用mmap。分配这种内存的大区域可能要容易得多,然后为你的内容提供“分配功能”。您可以使用virtualprotect以及Linux中相应的功能,但我认为首先分配为可执行文件是更好的选择。我不相信你需要刷新指令缓存它已经将内存分配为可执行文件 - 至少在x86上肯定不会 - 而且由于你的指令是x86指令,我想这是一个公平的限制。

其次,您需要创建类似于代码的函数指针。这样的事情应该这样做:

typedef void (*funcptr)(void); 

funcptr f = reinterpret_cast<funcptr>(&code_[0]); 

应该这样做。