简体   繁体   中英

does brk and sbrk round the program break to the nearest page boundary?

My question is as tilte says, accroding to my text book

int brk(void *end_data_segment);

The brk() system call sets the program break to the location specified by end_data_segment. Since virtual memory is allocated in units of pages, end_data_segment is effectively rounded up to the next page boundary.

and since on Linux, sbrk() is implemented as a library function that uses the brk() system call, so I expect that both function will round program break to the next page boundary. but when I test on a x86_64 Linux machine(ubuntu), it turns out both functions move the program break to the exact position as requested(I tried using brk, result is the same).

    int main(int argc, char *argv[])
    {
       void *ori = sbrk(100);
       printf("original program break at %p\n", ori);
       void *now = sbrk(0);
       printf("program break now at %p\n", now);
      return 0;
  }

this is the output

original program break at 0x56491e28f000
program break now at 0x56491e28f064

so what's going on here?

brk allocates/deallocates pages. That implementation detail based on the fact that the smallest unit of data for memory management in a virtual memory operating system is a page is transparent to the caller, however.

In the Linux kernel, brk saves the unaligned value and uses the aligned value to determine if pages need to be allocated/deallocated:

asmlinkage unsigned long sys_brk(unsigned long brk)
{
[...]
    newbrk = PAGE_ALIGN(brk);
    oldbrk = PAGE_ALIGN(mm->brk);
    if (oldbrk == newbrk)
        goto set_brk;
[...]
    if (do_brk(oldbrk, newbrk-oldbrk) != oldbrk)
        goto out;
set_brk:
    mm->brk = brk;
[...]
}

As for sbrk : glibc calls brk and maintains the (unaligned) value of the current program break ( __curbrk ) in userspace:

void *__curbrk;
[...]
void *
__sbrk (intptr_t increment)
{
  void *oldbrk;
  if (__curbrk == NULL || __libc_multiple_libcs)
    if (__brk (0) < 0)          /* Initialize the break.  */
      return (void *) -1;
  if (increment == 0)
    return __curbrk;
  oldbrk = __curbrk;
[...]
  if (__brk (oldbrk + increment) < 0)
    return (void *) -1;
  return oldbrk;
}

Consequently, the return value of sbrk does not reflect the page alignment that happens in the Linux kernel.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM