我正在使用sys_brk syscall在堆中动态分配内存.我注意到在获取当前的休息位置时,我通常会获得类似于以下内容的值:
mov rax, 0x0C
mov rdi, 0x00
syscall
结果是
rax 0x401000
该值通常对齐512个字节.因此,我想问一下中断值是否有对齐要求?还是我们可以按照自己的方式调整它的位置?
解决方法:
内核确实以字节粒度跟踪中断.但是,如果您完全关心性能,请不要将其直接用于少量分配.
评论中有一些关于内核将中断舍入到页面边界的讨论,但事实并非如此. The implementation of sys_brk
使用了它(添加了我的注释,因此在上下文之外很有意义)
newbrk = PAGE_ALIGN(brk); // the syscall arg
oldbrk = PAGE_ALIGN(mm->brk); // the current break
if (oldbrk == newbrk)
goto set_brk; // no need to map / unmap any pages, just update mm->brk
这检查中断是否移至另一页,但最终mm-> brk = brk;将当前中断设置为传递给系统调用的确切参数(如果有效).如果当前中断始终是页面对齐的,则内核将不需要PAGE_ALIGN().
当然,内存保护至少具有页面粒度(如果内核选择使用匿名大页面进行此映射,则可能具有大页面).所以you can access memory out to the end of the page containing the break without faulting.这就是为什么内核代码只是检查中断是否移至其他页面以跳过map / unmap逻辑,但仍会更新实际brk的原因.
AFAIK,没有任何东西将中断上方的映射内存用作暂存空间,因此它不像堆栈指针下方的内存可以被异步破坏.
brk只是内核内置的一个简单的内存管理系统.系统调用非常昂贵,因此如果您关心性能,则应该跟踪用户空间中的内容,并且仅在需要新页面时才进行系统调用.直接对较小的分配使用sys_brk会对性能造成严重影响,尤其是在启用Meltdown Spectre缓解功能的内核中(使系统调用更加昂贵,例如成千上万个时钟周期TLB和分支预测无效,而不是数百个时钟周期).