【问题标题】:What is the aligment requirements for sys_brksys_brk 的对齐要求是什么
【发布时间】:2018-07-29 23:33:32
【问题描述】:

我正在使用 sys_brk 系统调用在堆中动态分配内存。我注意到在获取当前中断位置时,我通常会得到类似于以下的值:

mov rax, 0x0C
mov rdi, 0x00
syscall

结果

rax   0x401000

该值通常以 512 字节对齐。所以想问一下break值有一些对齐要求吗?或者我们可以按照我们想要的方式错位?

【问题讨论】:

  • 传统上,对齐要求是1,如中,没有对齐要求。
  • 确实!这由程序员来管理。
  • 请注意,内存保护只有页面粒度,因此操作系统只能对硬件进行编程以将整个页面映射到您的虚拟地址空间。 IDK 如果有任何东西会在与中断相同的页面中踩到字节,但在您“拥有”的部分之外,但您绝对可以访问它们而不会出错。浪费 CPU 时间进行系统调用以以小于 4k 的页面增量移动中断没有多大意义,除非您真的想要很小的代码大小并且不想跟踪用户空间中的任何内容。跨度>
  • 内核代码aligns the break to page size(由 Peter 解释)。
  • x86 的页面大小为 4k。以 x86 为目标时,您无需在运行时查询它。其他一些架构可以为 non-hugepage pagesize 选择不同的大小,但 x86 固定为 4k。

标签: linux assembly heap-memory x86-64 sbrk


【解决方案1】:

内核确实以字节粒度跟踪中断。但是,如果您完全关心性能,请不要将它直接用于小分配。


在 cmets 中有一些关于内核将中断舍入到页面边界的讨论,但事实并非如此。 The implementation of sys_brk 使用它(添加了我的 cmets,因此脱离上下文也有意义)

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。这就是为什么内核代码只是检查中断是否移动到不同的页面以跳过映射/取消映射逻辑,但仍会更新实际的 brk。

AFAIK,没有任何东西会使用 break 上方的映射内存作为暂存空间,因此它不像堆栈指针下方的内存可以被异步破坏。

brk 只是一个内置于内核的简单内存管理系统。系统调用很昂贵,因此如果您关心性能,您应该跟踪用户空间中的内容,并且只在需要新页面时才进行系统调用。 直接使用sys_brk 进行微小分配对性能很不利,尤其是在启用了 Meltdown + Spectre 缓解的内核中(使系统调用更加昂贵,例如数万个时钟周期 + TLB 和分支预测失效,而不是数百个时钟周期)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-11-17
    • 1970-01-01
    • 1970-01-01
    • 2016-03-04
    • 2014-03-30
    • 2020-12-08
    相关资源
    最近更新 更多