Чому стеки зазвичай ростуть вниз?


95

Я знаю, що в архітектурах, з якими я особисто знайомий (x86, 6502 та ін.), Стек зазвичай росте вниз (тобто кожен елемент, що надходить у стек, призводить до зменшеного SP, а не до збільшеного).

Мені цікаво про історичне обгрунтування цього. Я знаю, що в уніфікованому адресному просторі зручно запускати стек на протилежному кінці сегмента даних (скажімо), тому існує проблема лише в тому випадку, якщо обидві сторони стикаються посередині. Але чому стек традиційно отримує верхню частину? Особливо з огляду на те, як це протилежність «концептуальній» моделі?

(І зауважте, що в архітектурі 6502 стек також зростає вниз, хоча він обмежений однією 256-байтовою сторінкою, і цей вибір напрямку виглядає довільним.)

Відповіді:


52

Що стосується історичного обґрунтування, то я не можу сказати напевно (бо я їх не розробляв). Мої думки з цього приводу полягають у тому, що для початкових процесорів встановлено початковий лічильник програм 0, і це було природним бажанням запустити стек з іншого кінця і рости вниз, оскільки їх код, природно, росте вгору.

Окрім того, зауважимо, що це налаштування лічильника програми на 0 при перезавантаженні стосується не всіх ранніх процесорів. Наприклад, Motorola 6809 отримає лічильник програми з адрес, 0xfffe/fщоб ви могли почати працювати в довільному місці, залежно від того, що було надано за цією адресою (зазвичай, але жодним чином не обмежуючись ПЗУ).

Одне з перших дій, які деякі історичні системи повинні зробити, - це сканувати пам’ять зверху, поки вона не знайде місце, яке зчитує те саме записане значення, щоб вона знала фактично встановлену оперативну пам’ять (наприклад, z80 з адресовим простором 64K не обов'язково мали 64 КБ або оперативну пам'ять, насправді 64 Кб були б масовими в мої перші дні). Як тільки він знайшов верхню фактичну адресу, він встановив би вказівник стека відповідним чином, а потім міг би розпочати виклик підпрограм. Це сканування, як правило, здійснюється за допомогою запущеного коду процесора в ПЗУ в рамках запуску.

Що стосується зростання стеків, не всі вони ростуть вниз, див. Цю відповідь для деталей.


1
Мені подобається історія стратегії виявлення оперативної пам'яті Z80. Має певний сенс, що текстові сегменти викладені зростаючими - попередні програмісти мали дещо більш безпосередній контакт із наслідками цього, ніж стек. Дякуємо paxdiablo. Вказівник на набір альтернативних форм реалізації стека також надзвичайно цікавий.
Ben Zotto

Хіба пам’ять раннього дня не має способу повідомити про її розмір, і нам доводиться обчислювати її вручну?
phuclv

1
@ LưuVĩnhPhúc, я повинен припустити, що ти за мною покоління (або два). Я все ще пам’ятаю метод TRS-80 модель 3 для отримання дати та часу, коли запитував у користувача під час завантаження. Наявність сканера пам’яті для встановлення верхньої межі пам’яті вважалося сучасним сучасним :-) Чи можете ви уявити, що могло б статися, якби Windows запитував час або скільки пам’яті ви мали при кожному завантаженні?
paxdiablo

1
Справді, в документації Zilog Z80 сказано, що частина запускається шляхом встановлення реєстру ПК на 0000h та виконання. Він встановлює режим переривання на 0, відключає переривання та встановлює регістри I та R також на 0. Після цього воно починає виконуватися. О 0000h він починає запускати код. ТОЙ код повинен ініціалізувати покажчик стека, перш ніж він може викликати підпрограму або активувати переривання. Який продавець продає Z80, який поводиться так, як ви описуєте?
MikeB

1
Майк, вибач, я повинен був бути яснішим. Коли я сказав, що процесор сканує пам'ять, я не мав на увазі, що це особливість самого процесора. Насправді цим керували з програми в ПЗУ. Я уточню.
paxdiablo

21

Одне гарне пояснення, яке я чув, було те, що в минулому деякі машини могли мати лише підписані зсуви, тому вам потрібно, щоб стек рос вниз, щоб ви могли вразити місцевих жителів, не втрачаючи додаткових вказівок, щоб підробити негативний зсув.


7

Стенлі Мазор (архітектор 4004 та 8080) пояснює, як було обрано напрямок зростання стека для 8080 (і врешті-решт для 8086) в "Мікропроцесори Intel: 8008 до 8086" :

Вказівник стека був обраний для запуску "вниз" (при цьому стек просувався до нижчої пам'яті), щоб спростити індексацію в стек з програми користувача (позитивне індексування) та спростити відображення вмісту стека з передньої панелі.


6

Однією з можливих причин може бути те, що це спрощує вирівнювання. Якщо ви помістите локальну змінну в стек, яка повинна бути розміщена на 4-байтовій межі, ви можете просто відняти розмір об'єкта від покажчика стека, а потім обнулити два нижні біти, щоб отримати належним чином вирівняну адресу. Якщо стек росте вгору, забезпечення вирівнювання стає дещо складнішим.


1
Комп’ютери не віднімають; вони додають у комплімент 2. Все, що робиться шляхом віднімання, справді робиться шляхом додавання. Зверніть увагу, комп’ютери мають суматори, а не віднімачі.
jww

1
@jww - це різниця без різниці. Я міг би твердити, що комп’ютери не додають, що вони лише віднімають! Для цілей цієї відповіді це насправді не має значення - але більшість ALU будуть використовувати схему, яка підтримує як додавання, так і віднімання з однаковою продуктивністю. Тобто, хоча A - Bконцептуально може бути реалізовано як A + (-B)(тобто окремий етап заперечення B), на практиці це не є.
BeeOnRope

@jww Ваш nitpick неправильний для ранніх комп’ютерів - потрібен був деякий час, щоб доповнити двоє, і поки це не сталося, існували комп’ютери, які використовували замість цього доповнення та знак і величину, а може й інші речі. З цими реалізаціями цілком могла бути перевага додавання чи віднімання. Отже, за відсутності додаткової інформації, неправильно виключати це як можливий фактор, що впливає на вибір схеми вирішення, як напрям стека.
mtraceur

4

IIRC стек росте вниз, тому що купа росте вгору. Могло бути і навпаки.


5
Зростаюча купа дозволяє в деяких випадках ефективно перерозподілити, але зростаюча купа майже ніколи цього не робить.
Пітер Кордес,

Чому @PeterCordes?
Яшас,

3
@Yashas: тому що після об’єкта realloc(3)потрібно більше місця , щоб просто розширити відображення без копіювання. Повторний перерозподіл того самого об’єкта можливий, коли за ним йде довільна кількість невикористаного простору.
Пітер Кордес,

2

Я вважаю, що це суто дизайнерське рішення. Не всі з них зростають вниз - див. Цей потік SO для гарного обговорення напряму зростання стека на різних архітектурах.


1

Я вважаю, що Конвенція розпочалася з IBM 704 та її сумнозвісного "реєстру декрементів". Сучасна мова могла б назвати це зміщеним полем інструкції, але справа в тому, що вони пішли вниз , а не вгору .


1

Ще лише на 2 с:

Окрім усіх згаданих історичних обґрунтувань, я абсолютно впевнений, що немає жодної причини, яка б відповідала сучасним процесорам. Всі процесори можуть приймати підписані зсуви, і максимізація відстані між купою та стеком є ​​досить спірною з тих пір, як ми почали працювати з декількома потоками.

Я особисто вважаю це недоліком дизайну безпеки. Якби, скажімо, дизайнери архітектури x64 змінили напрямок зростання стека, більшість переповнення буфера стека були б усунені - це свого роду велика справа. (оскільки струни ростуть вгору).


0

Я не впевнений, але ще колись я програмував VAX / VMS. Здається, я пам’ятаю, як одна частина пам’яті (купа ??) зростала, а стек опускався. Коли вони познайомились, тоді у вас не вистачало пам’яті.


1
Це правда, але чому тоді купа росте вгору, а не навпаки?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

0

Однією з переваг низхідного зростання стека в мінімальній вбудованій системі є те, що один шматок оперативної пам'яті може бути надмірно зіставлений як на сторінку O, так і на сторінку 1, дозволяючи призначати нульові змінні сторінки, починаючи з 0x000 і стек, що зростає вниз від 0x1FF, максимізуючи сума, яку йому довелося б збільшити до перезапису змінних.

Однією з оригінальних цілей дизайну 6502 було те, що він міг поєднуватися, наприклад, з 6530, що призвело до створення двокристальної мікроконтролерної системи з 1 КБ ПЗУ програми, таймером, введенням-виведенням і спільним використанням 64 байт оперативної пам'яті між стеком і нульовими змінними сторінки. Для порівняння, мінімальна вбудована система того часу, заснована на 8080 або 6800, мала б чотири-п’ять мікросхем.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.