Почему адрес стека растет в сторону уменьшения адресов памяти? - PullRequest
29 голосов
/ 30 декабря 2010

Я читал в учебниках, что стек увеличивается за счет уменьшения адреса памяти;то есть от более высокого адреса к более низкому адресу.Это может быть плохой вопрос, но я не понял концепцию правильно.Вы можете объяснить?

Ответы [ 4 ]

52 голосов
/ 30 декабря 2010

Во-первых, это зависит от платформы.В некоторых архитектурах стек выделяется из нижней части адресного пространства и растет вверх.

Принимая во внимание архитектуру, подобную x86, стек, выросший сверху вниз из адресного пространства, идея довольно проста:

===============     Highest Address (e.g. 0xFFFF)
|             |
|    STACK    |
|             |
|-------------|  <- Stack Pointer   (e.g. 0xEEEE)
|             |
.     ...     .
|             |
|-------------|  <- Heap Pointer    (e.g. 0x2222)
|             |
|    HEAP     |
|             |
===============     Lowest Address  (e.g. 0x0000)

Чтобы увеличить стек, вы должны уменьшить указатель стека:

===============     Highest Address (e.g. 0xFFFF)
|             |
|    STACK    |
|             |
|.............|  <- Old Stack Pointer (e.g. 0xEEEE)
|             |
| Newly       |
| allocated   |
|-------------|  <- New Stack Pointer (e.g. 0xAAAA)
.     ...     .
|             |
|-------------|  <- Heap Pointer      (e.g. 0x2222)
|             |
|    HEAP     |
|             |
===============     Lowest Address    (e.g. 0x0000)

Как видите, чтобы увеличить стек, мы уменьшили указатель стека с 0xEEEE до0xAAAA, тогда как для увеличения кучи необходимо увеличить указатель кучи.

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

Вы можете спросить, почему стек должен расти вниз.Ну, как я уже говорил, некоторые архитектуры делают наоборот: куча растет вниз, а стек растет вверх.Имеет смысл размещать стек и кучу на противоположных сторонах, поскольку это предотвращает перекрытие и позволяет обеим областям свободно расти, если у вас достаточно доступного адресного пространства.

Еще один правильный вопрос может быть: не предполагается ли программауменьшить / увеличить сам указатель стека?Как архитектура может навязывать программисту одно поверх другого?Почему это не так зависит от программы, как это зависит от архитектуры?Хотя вы можете в значительной степени бороться с архитектурой и каким-то образом убрать свой стек в противоположном направлении, некоторые инструкции, в частности call и ret, которые напрямую изменяют указатель стека, собираются принять другое направление, что приводит к путанице.

21 голосов
/ 30 декабря 2010

В настоящее время это в значительной степени потому, что это было сделано в течение длительного времени, и многие программы предполагают, что это было сделано, и нет никакой реальной причины для его изменения.

Назад, когда динозавры бродили по земле, и у компьютеров было 8 КБ памяти, если вам повезло, это была важная оптимизация пространства. Вы помещаете дно стека в самый верх памяти, увеличиваясь вниз, и вы помещаете программу и ее данные в самое дно, увеличивая область malloc. Таким образом, единственным ограничением размера стека был размер программы + куча, и наоборот. Если вместо этого стек начинался с 4 КБ (например) и увеличивался, куча никогда не могла бы превысить 4 КБ (минус размер программы), даже если программе требовалось всего несколько сотен байтов стека.

0 голосов
/ 25 июня 2019

На x86 основной причиной увеличения стека в сторону уменьшения адресов памяти является то, что инструкция PUSH уменьшает указатель стека:

Уменьшает указатель стека и затем сохраняет исходный операнд сверхустека.

См. стр.4-511 в Intel® 64 и IA-32 ArchitecturesSoftware Руководство разработчика .

0 голосов
/ 25 декабря 2018

Man CLONE: аргумент child_stack указывает местоположение стека, используемого дочерним процессом.Поскольку дочерний и вызывающий процессы могут совместно использовать память, дочерний процесс не может выполняться в том же стеке, что и вызывающий процесс.Поэтому вызывающий процесс должен установить пространство памяти для дочернего стека и передать указатель на это пространство в clone ().Стеки растут вниз на всех процессорах под управлением Linux (кроме процессоров HP PA), поэтому child_stack обычно указывает на самый верхний адрес пространства памяти, настроенного для дочернего стека.

...