прерывает ли brk и sbrk программу до ближайшей границы страницы?

Мой вопрос, как говорит тилте, согласно моему учебнику

int brk(void *end_data_segment);

Системный вызов brk() устанавливает прерывание программы в положение, указанное end_data_segment. Поскольку виртуальная память выделяется в единицах страниц, end_data_segment эффективно округляется до границы следующей страницы.

и поскольку в Linux sbrk() реализована как библиотечная функция, использующая системный вызов brk(), поэтому я ожидаю, что обе функции будут округлять прерывание программы до границы следующей страницы. но когда я тестирую на Linux-машине x86_64 (ubuntu), оказывается, что обе функции перемещают прерывание программы точно в требуемое положение (я пытался использовать brk, результат тот же).

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

это результат

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

так что здесь происходит?


person zenxy    schedule 24.12.2020    source источник
comment
is effectively rounded up не значит вернется,   -  person KamilCuk    schedule 24.12.2020


Ответы (1)


brk выделяет/освобождает страницы. Однако эта деталь реализации, основанная на том факте, что наименьшей единицей данных для управления памятью в операционной системе с виртуальной памятью является страница, прозрачна для вызывающей стороны.

В ядре Linux brk сохраняет невыровненное значение и использует выровненное значение, чтобы определить, нужно ли выделять/освобождать страницы:

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;
[...]
}

Что касается sbrk: glibc вызывает brk и поддерживает (невыровненное) значение текущего прерывания программы (__curbrk) в пользовательском пространстве:

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

Следовательно, возвращаемое значение sbrk не отражает выравнивание страниц, происходящее в ядре Linux.

person horstr    schedule 03.01.2021