Прежде всего, вы не хотите
MAP_GROWSDOWN
, и это не то, как работает стек основных потоков. Анализ отображения памяти процесса с помощью pmap. [стек] Ничто не использует это, и почти ничто не должно использовать это. Материал на странице руководства, в котором говорится, что он «используется для стеков», неверен и его следует исправить.
Я подозреваю, что это может быть ошибка (потому что ничто не использует это так, обычно никто не заботится или даже замечает, если это ломается.)
Ваш код работает для меня, если я изменю вызов
mmap
, чтобы отобразить более 1 страницы. В частности, я попробовал
4096 * 100
. Я использую Linux 5.0.1 (Arch Linux) на голом железе (Skylake).
/proc/PID/smaps
показывает флаг
gd
.
И затем (при однократном шаге asm) запись
maps
действительно меняется на более низкий начальный адрес, но тот же конечный адрес, поэтому он буквально растет вниз, когда я начинаю с сопоставления 400k. Это дает начальное выделение 400 КБ выше адреса возврата, которое увеличивается до 404 КБ при запуске программы. (Размер для отображения
_GROWSDOWN
не является пределом роста или чем-то в этом роде.)
https://bugs.centos.org/view.php?id=4767 может быть связано; что-то изменилось между версиями ядра в CentOS 5.3 и 5.5. И / или это было связано с работой на виртуальной машине (5.3), а не с ростом и отказом от голого металла (5.5).
Я упростил C, чтобы использовать
ptr[ и т. Д.
int main(void){
volatile char *ptr = mmap(NULL, 4096*100,
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_STACK | MAP_GROWSDOWN,
Компиляция с gcc дает asm, который хорошо подходит для одного шага.
Кстати, разные слухи об удалении флага из glibc явно ошибочны. Этот источник компилируется, и ясно, что он также поддерживается ядром, а не игнорируется. (Хотя поведение, которое я вижу с размером 4096 вместо 400 кБ, в точности соответствует тому, что флаг молча игнорируется. Однако gd
VmFlag все еще присутствует в
smaps
, поэтому он не игнорируется на этом этапе.)
Я проверил, и было место для его роста, не приближаясь к другому отображению. Итак, IDK, почему он не вырос, когда отображение GD было всего 1 страницей. Я попробовал пару раз, и он каждый раз работал с ошибками. С большим начальным отображением это никогда не нарушалось.
Оба раза были с сохранением возвращаемого значения mmap (первой страницы собственно сопоставления), затем хранилище на 4095 байт ниже этого.