作者:杨斜2602934873 | 来源:互联网 | 2022-10-16 12:02
我最近正在研究一些JIT编译器。据我所知,JIT是一种将一些脚本语言代码即时编译为本地代码的技术(在执行之前)。正如我想象的那样,这种编译器的内部结构使我发现,必须在生成的本机代码所在的位置上放置一段动态分配的缓冲区。但是然后我们需要一种方法来从保存数据的缓冲区内开始运行代码。我的意思是,char[]
由于安全隐患,操作系统不能阻止您这样做,因此您不能只是将一些代码放入a 然后跳入执行。必须有某种方法将缓冲区标记为可执行文件。考虑以下天真的方法:
#include
void *jit_some_native_code(void) {
void *code_segment = malloc(1024);
/*
* bla bla bla...
* Generate code into this code_segment.
*/
return code_segment;
}
int main(void) {
void *code = jit_some_native_code();
/*
* How can I start executing instruction in code?
*/
typedef void (*func_ptr_t)(void);
/*
* This won't work. OS bans you doing so.
*/
((func_ptr_t)code)();
}
在Ubuntu上,该代码将运行,但会以状态代码26退出。鉴于C的类型不安全特性,该代码可以编译,但对于C ++,编译器只会使您停止。这是否意味着JIT必须绕过编译器以及设置可执行标志?
编辑:此外mprotect
,如果使用mmap
,还可以指定页面映射权限:
PROT_EXEC Pages may be executed.
PROT_READ Pages may be read.
PROT_WRITE Pages may be written.
PROT_NONE Pages may not be accessed.
这样,页面将具有可执行权限。
1> Nina..:
如果要使堆中的区域成为可执行文件,则可以使用mprotect。
int main() {
typedef void (*func_t)(void);
void *code = &some_jit_func;
int pagesize = getpagesize();
mprotect(code, pagesize,PROT_EXEC);
((func_t)code)();
}
您还可以使用PROT_READ / PROT_WRITE对标志进行OR
@ryyker号。正如其[手册](https://pubs.opengroup.org/onlinepubs/9699919799/functions/mprotect.html)中明确提到的那样,`mprotect` _changes_一页内存的访问权限。除此之外,大多数操作系统将拒绝执行可执行和可写的页面。