使程序执行数据的最佳方法是什么。说,我为 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 (*)();
并调用它。但是有一些困难:
VirtualProtect(Ex)
(+ FlushInstructionCache
)吗?在Linux上类似的东西?答案 0 :(得分:2)
首先,您需要将代码分配为可执行文件[在Windows中使用带有“可执行”标志的VirtualAlloc,并使用“MAP_EXECUTABLE”作为标志之一]使用mmap。分配这种内存的大区域可能要容易得多,然后为你的内容提供“分配功能”。您可以使用virtualprotect以及Linux中相应的功能,但我认为首先分配为可执行文件是更好的选择。我不相信你需要刷新指令缓存它已经将内存分配为可执行文件 - 至少在x86上肯定不会 - 而且由于你的指令是x86指令,我想这是一个公平的限制。
其次,您需要创建类似于代码的函数指针。这样的事情应该这样做:
typedef void (*funcptr)(void);
funcptr f = reinterpret_cast<funcptr>(&code_[0]);
应该这样做。