Linux内核5.8及以上版本如何分配可执行内存?
内核5.8及以上版本分配可执行内存的替代方案
背景说明
自Linux 5.8内核发布后,__vmalloc()函数的签名发生变更:
旧签名:
void *__vmalloc(unsigned long size, gfp_t gfp_mask, pgprot_t prot)
新签名:
void *__vmalloc(unsigned long size, gfp_t gfp_mask)
这意味着无法再通过该函数直接指定内存属性来分配可执行内存。常规适配代码如下:
#if LINUX_VERSION_CODE < KERNEL_VERSION(5,8,0) return __vmalloc(len, GFP_KERNEL, PAGE_KERNEL_EXEC); #else return __vmalloc(len, GFP_KERNEL); #endif
但这种适配方式下,若不使用内核noexec参数,内核5.8及以上版本无法通过vmalloc分配可执行内存。请问此时有什么替代方案?
可行替代方案
使用
vmalloc_exec()专用接口
内核提供了vmalloc_exec()函数,专门用于分配具备可执行属性的虚拟内存,内部已封装好页属性设置逻辑,直接适配5.8及以上内核:void *exec_buf = vmalloc_exec(size); if (!exec_buf) { // 处理内存分配失败逻辑 }先分配内存再修改页属性
若需要更灵活的内存分配控制,可先通过vmalloc()或__vmalloc()分配普通内存,再调用set_memory_x()将目标内存区域设置为可执行:void *buf = vmalloc(size); if (!buf) { // 处理分配失败 } // 按页对齐计算需要修改的页数 unsigned int pages = PAGE_ALIGN(size) >> PAGE_SHIFT; if (set_memory_x((unsigned long)buf, pages) != 0) { // 修改属性失败,释放已分配内存 vfree(buf); buf = NULL; }注意:
set_memory_x()要求操作的内存区域页对齐,且部分内核配置可能限制此类内存属性修改操作,需确保权限足够。使用
__vmalloc_node_range()指定页属性
如果需要指定内存节点、对齐规则等复杂参数,可使用__vmalloc_node_range()函数,该函数保留了pgprot_t prot参数,直接传入PAGE_KERNEL_EXEC即可分配可执行内存:void *exec_buf = __vmalloc_node_range(size, 1, VMALLOC_START, VMALLOC_END, GFP_KERNEL, PAGE_KERNEL_EXEC, 0, NUMA_NO_NODE, __builtin_return_address(0)); if (!exec_buf) { // 处理分配失败逻辑 }该函数参数较多,需注意对齐值(此处为1表示按字节对齐)、内存范围、NUMA节点编号等参数的正确设置。
内容的提问来源于stack exchange,提问作者Xander
相关产品推荐
相关产品推荐

