Goo*_*ofy 13 linux assembly arm x86-64
我正在研究应用程序(用C++编写),它在运行时生成一些机器代码(现在是Linux,x86-64,但我计划在ARM上进行迁移).接下来,它将生成的代码存储在内存中并通过跳转到内存位置来执行它.很长一段时间我都遇到了分配可执行内存的问题,但我终于解决了它:
uint8_t *memory = mmap (NULL, length, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
Run Code Online (Sandbox Code Playgroud)
到目前为止它的确有效,但我不确定它是否是做这些事情的优雅方式.我想知道可执行加载器是如何做到的
bdo*_*lan 13
这实际上是可执行加载器的工作方式; 在他们的情况下,他们执行一个mmap文件,而不是匿名映射,但除此之外,它基本上是相同的.
请注意,最好不要同时拥有写入和执行访问权限,因为它会使某些类型的安全漏洞更容易.您可以使用mprotect在初始映射后调整保护标志.
Tho*_*nin 13
您的解决方案主要是应该做的事情:让操作系统将页面视为可执行文件.但是,某些操作系统将强制执行所谓的W ^ X策略,其中页面可以是可写的或可执行的,但不能同时进行.对于这样的系统(即OpenBSD,但也有修改过的Linux版本也可以这样做),mmap()上面的内容将失败.因此,完整的解决方案需要首先使用mmap()和分配一些页面PROT_READ | PROT_WRITE,然后用于在生成代码时将mprotect()页面切换到PROT_READ | PROT_EXEC.
即使操作系统没有强制执行W ^ X,mprotect()强烈建议进行调用,因为缓存效应(数据访问和执行在CPU中相互独立;您希望确保CPU将使用新编写的操作码而不是之前RAM中的内容; mprotect()包含必要的魔力).