linux 64位8字节对齐,在Linux中对sbrk(0)的初始调用是否总是返回一个与8个字节对齐的值(或者在32位系统的情况下为4)(Is the initial call to sbrk(0) ...

在Linux中对sbrk(0)的初始调用是否总是返回一个与8个字节对齐的值(或者在32位系统的情况下为4)(Is the initial call to sbrk(0) in Linux always return a value aligned to 8 bytes ( or 4 in case of 32-bit systems))

我正在研究这里定义的malloc的实现:

作者创建一个自然地在4字节边界上对齐的元数据结构,然后在元数据结构之后将x字节的请求与4字节边界对齐,该元数据结构实际上充当块的头部。 pdf指出,由于元数据和请求现在已对齐,因此结果数据将完全对齐。 如果对sbrk()的第一次调用返回与4字节边界对齐的堆的基址,则结果可以解决。 sbrk()总是返回初始调用中的4字节(或64位系统情况下为8字节)对齐的地址吗?

I was looking into the implementation of malloc defined here:

The author create a metadata structure that is naturally aligned on a 4 byte boundary and then aligns a request for x bytes to a 4 byte boundary after the metadata structure which effectively acts as a header for the block. The pdf states that since the metadata and the request are now aligned , the resultant data will be completely aligned. The result works out if the first call to sbrk() returns a base address for the heap that is aligned to a 4-byte boundary. Does sbrk() always return a 4 byte (or 8 byte in case of 64-bit systems) aligned address in the initial call ?

原文:https://stackoverflow.com/questions/27340800

更新时间:2020-02-23 21:57

最满意答案

brk和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()和sbrk()更改程序中断的位置,该位置定义进程数据段的结束(即,程序中断是未初始化数据段结束后的第一个位置)。 增加程序中断会产生为进程分配内存的效果; 减少休息时间会释放内存。

单位化数据段也称为BSS。 这里的关键字是段 ,因此初始值很可能始终是页面对齐的。

如果您想要安全并检查,您可以通过使用页面大小的模数(您可以通过getpagesize查询)来验证初始地址。

更新:所以我好奇并且挖了一点。 在man-page中,我已经读过brk和sbrk是在内核的sys_brk上实现的。 它在内核源代码中的实现可以在mm/mmap.c找到(对于没有内存管理单元的系统,可以找到mm/mmap.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_som.c和处理HP-UX SOM格式的fs/binfmt_som.c (之前从未听说过)也是如此。 还有fs/binfmt_flat.c ,它设置初始的brk值,但没有明确对齐; 这里的值是隐式对齐的。 所以看起来初始值始终是页面对齐的。 至少它保证与ELF文件页面对齐,这是我们关心的“普通”系统。

glibc简单地包装sys_brk并添加簿记以正确实现sbrk 。 因此glibc的brk行为是内核的行为,返回值sys_brk存储在内部隐藏变量__curbrk以便sbrk可以正确计算新地址。

The standard for brk and sbrk explicitly does not specify whether the returned address is aligned in any way. On Mac OS X (and maybe other BSD systems) the sizes/addresses are page-aligned, but on Linux no such rounding takes place as can easily be tested with this little program:

#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;

}

On one of my systems, the output was:

Initial brk: 0x602000

New brk: 0x602001

But you asked for the initial call. The Linux man-page states:

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.

The unitialized data segment is also known as BSS. The keyword here is segment, so it's very likely the initial value is always page-aligned.

If you want to be on the safe side and check, you can verify the initial address by taking the modulo with the page size (which you can query via getpagesize).

Update: So I was curious and dug around a bit more. In the man-page, I already read that brk and sbrk are implemented atop the kernel's sys_brk. Its implementation in the kernel source can be found in mm/mmap.c (or mm/nommu.c for systems without a Memory Management Unit; we'll ignore this one). In the brk implementation in mm/mmap.c, we find this line:

newbrk = PAGE_ALIGN(brk);

("brk" here is the argument, not the function.) So the kernel does do page aligning… sort of: while the calculations are done with the page-aligned values and any necessary memory allocation is page-aligned, the value stored for the brk is actually the pointer value you passed:

mm->brk = brk;

So in the user-space it doesn't look like any page-algning took place even though the kernel did. I looked at versions 3.17.5 and 2.4.37, the behaviour is the same.

Regarding the initial value, in fs/binfmt_elf.c (which implements ELF linking) we find a function set_brk which sets the initial "brk" value (mm->start_brk). This value is explicitly page-aligned. The same is true for fs/binfmt_aout.c which handles the old a.out format and fs/binfmt_som.c which handles HP-UX SOM format (never heard of it before). There's also fs/binfmt_flat.c which sets the initial brk value but doesn't align explicitly; the value is implicitly aligned here. So it looks like the initial value is always page-aligned. At least it's guaranteed to be page-aligned for ELF files, which is what we care about for "normal" systems.

The glibc simply wraps sys_brk and adds bookkeeping to correctly implement sbrk. So glibc's brk behaviour is that of the kernel, the return value sys_brk is stored in an internal hidden variable __curbrk so that sbrk can calculate the new address correctly.

2014-12-07

相关问答

你正在做错误的指针运算。 sysconf(_SC_PAGESIZE)返回页面的大小(以字节为单位) 。 添加指向int的b ,将sizeof(int) * _SC_PAGESIZE到它。 运行这个: int *b = sbrk(0);

printf("b = %p\n", b);

printf("PAGESIZE = %d\n", sysconf(_SC_PAGESIZE));

void *bound = b + sysconf(_SC_PAGESIZE);

printf("bound = %p\

...

哪些因素影响这些业务的表现? 可能是编译器和编译器版本; 但是操作系统还是CPU造成/模型影响呢? 大多数处理器架构(和型号 - 请阅读我在本节中提到处理器架构的型号)。 编译器可能有一些影响,但是大多数编译器在这方面做得很好,所以处理器架构将比编译器有更大的影响。 操作系统将不会有任何影响(除了“如果您更改操作系统,您需要使用不同类型的编译器来更改编译器”),但这可能是一个小的影响。 正常的32位系统会使用现代CPU的64位寄存器吗? 这不可能。 如果系统处于32位模式,它将充当32位系统,额外

...

我不熟悉有问题的功能,但是: #if defined (__WIN32__)

#define F(X) VirtualAlloc(X)

#elif defined (__LINUX__) /* or whatever linux's define is */

#define F(X) sbrk(X)

#endif

不知道语法是否是100%(我是宏和C的新手),但总体思路应该起作用。 I'm not familiar with the functions in question but:

...

添加行 #include

在文件'mymalloc.c'的顶部,以便声明该函数 Add the line #include

At the top of the file 'mymalloc.c' so that the function is declared

好问题:) 问题是ds仍然设置为零,在64位模式下它不被使用。 所以,你需要重新加载它,它会工作。 更改初始测试push / pop以push $0x2b; pop %ds push $0x2b; pop %ds会做的伎俩: const unsigned char instructions[] = {

0x6a, 0x2b, // push $0x2b

0x1f, // pop %ds

我从32位程序中提取了0x2b值。 我只是想知道为什么push工作。 仔细看看

...

这是一个很大的话题。 您应该首先学习进入并了解保护模式 。 This is a huge topic. You should probably start by learning to enter and know protected mode.

brk和sbrk的标准明确没有指定返回的地址是否以任何方式对齐。 在Mac OS X(可能还有其他BSD系统)上,大小/地址是页面对齐的,但在Linux上没有这样的舍入,因为可以使用这个小程序轻松测试: #include

#include

int main() {

void *p;

p = sbrk(0);

printf("Initial brk: %p\n", p);

p = sbrk(1

...

数据和bss段是固定大小的。 因此,在这些细分结束后分配给流程的空间不属于这些细分市场; 它只是与它们相连。 并且该空间被称为堆空间并用于动态内存分配。 如果你想把它看作'扩展数据/ bss段',那也没关系。 它不会对程序的行为,或分配的空间或任何东西产生任何影响。 Mac OS X上的手册页显示你真的不应该使用它们: brk和sbrk函数是虚拟内存管理出现之前早期留下的历史好奇。 brk()函数将进程数据段(未初始化数据)的中断或最低地址设置为addr (紧接在bss之上)。 数据寻址在addr

...

好吧,正如Clement建议的那样,将“六”添加到隐藏包中并不起作用,但是开始了一系列的反复试验,最终导致了一个解决方案。 在“hiddenimports”测试不起作用后,我试着将'six'导入到我的Python代码中。 编译后的可执行文件不再显示此错误! 然而,它现在说,名为“包装”的包是必需的......我没有安装。 简而言之,从最初的问题开始,我这样做了: 使用'pip'安装'包装': sudo pip安装包装 将这些导入添加到我的主Python代码中: 进口六 进口包装 import pa

...

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值