standard for brk and sbrk明确没有指定返回的地址是否以任何方式对齐.在Mac OS X(可能还有其他BSD系统)上,大小/地址是页面对齐的,但在Linux上没有这样的舍入,因为可以使用这个小程序轻松测试:
#include
#include
int main() {
void *p;
p = sbrk(0);
printf("Initial brk: %p\n",p);
p = sbrk(1); // Increase the brk (returns OLD brk!)
p = sbrk(0); // Get the new brk
printf("New brk: %p\n",p);
return 0;
}
在我的一个系统上,输出是:
Initial brk: 0x602000
New brk: 0x602001
但你问了最初的电话. Linux手册页指出:
brk() and sbrk() change the location of the program break,which defines the end of the process’s data segment (i.e.,the program break is the first location after the end of the uninitialized data segment). Increasing the program break has the effect of allocating memory to the process; decreasing the break deallocates memory.
单位化数据段也称为BSS.这里的关键字是段,因此初始值很可能始终是页面对齐的.
如果您想要安全并检查,您可以通过获取页面大小的模数来验证初始地址(您可以通过getpagesize查询).
更新:所以我好奇并且挖了一点.在man-page中,我已经读过brk和sbrk是在内核的sys_brk上实现的.它在内核源代码中的实现可以在mm / mmap.c中找到(对于没有内存管理单元的系统,可以找到mm / nommu.c;我们将忽略这一点).在mm / mmap.c中的brk实现中,我们找到了这一行:
newbrk = PAGE_ALIGN(brk);
(“brk”这里是参数,而不是函数.)所以内核确实进行页面对齐…排序:虽然计算是使用页面对齐的值完成的,并且任何必要的内存分配是页面对齐的,但是存储的值是brk实际上是你传递的指针值:
mm->brk = brk;
因此,在用户空间中,即使内核确实发生了任何页面操作,它看起来也不像.我看了3.17.5和2.4.37版本,行为是一样的.
关于初始值,在fs / binfmt_elf.c(实现ELF链接)中,我们找到一个函数set_brk,它设置初始“brk”值(mm-> start_brk).该值明确是页面对齐的.对于处理旧的a.out格式的fs / binfmt_aout.c和处理HP-UX SOM格式的fs / binfmt_som.c(之前从未听说过),情况也是如此.还有fs / binfmt_flat.c,它设置初始brk值但没有明确对齐;这里的值是隐式对齐的.所以看起来初始值始终是页面对齐的.至少它保证与ELF文件页面对齐,这是我们关心的“普通”系统.
glibc简单地包装sys_brk并添加簿记以正确实现sbrk.因此glibc的brk行为是内核的行为,返回值sys_brk存储在内部隐藏变量__curbrk中,以便sbrk可以正确计算新地址.