Где на самом деле начинается выделенная память, когда я использую системный вызов brk
Я пытаюсь выделить немного памяти, используя sys_brk в сборке NASM/x86. sys_break возвращает новый адрес разрыва, который является концом сегмента данных, верно? Так где же находится моя вновь выделенная память? Я предположил, что он находится между старым значением разрыва и новым значением разрыва. Поэтому, если я выделю 64 байта памяти с помощью sys_brk, я смогу использовать следующие 64 байта, начиная со старого значения разрыва, которое я сохранил до вызова sys_brk. Я прав?
Мой ассемблерный код, который будет выделять память, будет выглядеть примерно так. https://gist.github.com/nikAizuddin/f4132721126257ec4345
И еще один побочный вопрос;
Я должен написать функцию в ассемблере, которая возвращает указатель на динамически распределенную память, и эта функция будет вызываться из программы на Си. Как я могу освободить этот блок памяти со стороны C моей программы? Достаточно ли будет просто позвонить free()?
1 ответ
brk(2)
Страница man (раздел: Различия ABI библиотеки C / ядра) описывает, как оболочка glibc реализована поверх системного вызова Linux, который возвращает новый brk в случае успеха или старый brk в случае сбоя.
Насколько я понимаю, память за пределами текущего перерыва не отображается. Адреса ниже текущего разрыва являются частью сегмента данных (в смысле data+bss+heap). В документах не ясно, должен ли разрыв быть выровнен по страницам. (т.е. вы можете sbrk(64) или только sbrk(4096)?)
Смотрите: Что делает системный вызов brk()? Ответ на этот вопрос имеет пример использования sbrk вместо malloc для code-golf. Так что да, старый перерыв - это адрес для возвращения. И, видимо, вы можете sbrk
любой прирост, а не только страницы.
Вы тот, кто пишет распределитель памяти. sbrk
просто позволяет получить больше от ОС, как mmap(MAP_ANONYMOUS)
но менее гибкий. Это не поможет вам отслеживать свободные блоки, чтобы вы могли использовать их для будущих распределений, вместо того, чтобы всегда получать больше от ОС.
Способ вернуть память, которую вы получили с sbrk
по телефону sbrk
с отрицательным аргументом. Очевидно, что для этого требуется шаблон использования "первым пришел - первым обслужен", поэтому в malloc только glibc использует sbrk
для небольших распределений (которые могут быть помещены в свободный список после освобождения, для раздачи будущим маллокам). Большие выделения лучше всего возвращать в ОС сразу, а не отображать, поэтому malloc использует glibc mmap
для тех.
Никогда не звони free(3)
на память вы не получили от malloc(3)
(или связанная функция, такая как strdup(3)
, что говорит в документах вы можете и должны free(3)
в память.) ИДК, что будет, если вы позвоните munmap
на странице памяти под перерывом программы. Возможно, это просто сработает, но тогда у вас будет задержка в вашем сегменте данных, которая может вызвать проблемы, если разрыв когда-либо уменьшится до этого уровня.
позже понял, что это не то, что вы спрашивали:
Самый простой способ получить текущий brk - просто вызвать его increment = 0
,
Это то, что Глибц malloc(3)
делает внутренне:
$ strace -e brk ls 2>&1 | m
brk(0) = 0x650000
brk(0) = 0x650000
brk(0x671000) = 0x671000
Страница руководства brk упоминает end(3)
, По-видимому, существуют глобальные переменные, которые расположены в конце сегментов текста, данных и bss. Тем не мение, &end
находится только "где-то рядом" с разрывом программы, поэтому malloc все еще должен вызвать sbrk(0), чтобы получить начальный разрыв.