Dlaczego stosy zwykle rosną w dół?

96

Wiem, że w architekturach, które osobiście znam (x86, 6502 itd.), Stos zwykle rośnie w dół (tj. Każdy element umieszczany na stosie skutkuje zmniejszeniem SP, a nie zwiększeniem).

Zastanawiam się, jakie jest historyczne uzasadnienie tego. Wiem, że w ujednoliconej przestrzeni adresowej wygodnie jest rozpocząć stos na przeciwległym końcu segmentu danych (powiedzmy), więc problem występuje tylko wtedy, gdy dwie strony zderzają się w środku. Ale dlaczego stos tradycyjnie otrzymuje górną część? Zwłaszcza biorąc pod uwagę, że jest to przeciwieństwo modelu „koncepcyjnego”?

(Zauważ, że w architekturze 6502 stos rośnie również w dół, mimo że jest ograniczony do pojedynczej strony 256-bajtowej, a ten wybór kierunku wydaje się arbitralny).

Ben Zotto
źródło

Odpowiedzi:

52

Co do historycznego uzasadnienia, nie mogę powiedzieć na pewno (ponieważ ich nie zaprojektowałem). Moje przemyślenia na ten temat są takie, że wczesne procesory miały swój pierwotny licznik programu ustawiony na 0 i naturalnym pragnieniem było rozpoczęcie stosu na drugim końcu i wzrost w dół, ponieważ ich kod naturalnie rośnie w górę.

Na marginesie należy zauważyć, że to ustawienie licznika programu na 0 podczas resetowania nie dotyczy wszystkich wczesnych procesorów. Na przykład Motorola 6809 pobierze licznik programu z adresów 0xfffe/f, abyś mógł rozpocząć pracę w dowolnej lokalizacji, w zależności od tego, co zostało dostarczone pod ten adres (zwykle, ale w żadnym wypadku nie ogranicza się do pamięci ROM).

Jedną z pierwszych rzeczy, które zrobiłyby niektóre systemy historyczne, byłoby skanowanie pamięci od góry do momentu znalezienia lokalizacji, która odczyta tę samą zapisaną wartość, aby znał faktyczną zainstalowaną pamięć RAM (np. Z80 z przestrzenią adresową 64K niekoniecznie miał 64K lub RAM, w rzeczywistości 64K byłby ogromny w moich pierwszych dniach). Gdy znalazł górny rzeczywisty adres, ustawiłby odpowiednio wskaźnik stosu i mógł rozpocząć wywoływanie podprogramów. To skanowanie byłoby generalnie wykonywane przez procesor uruchamiający kod w pamięci ROM jako część rozruchu.

Jeśli chodzi o wzrost stosów, nie wszystkie z nich rosną w dół, szczegóły w tej odpowiedzi .

paxdiablo
źródło
1
Podoba mi się historia dotycząca strategii wykrywania pamięci Z80 RAM. Ma to jakiś sens, że segmenty tekstu układają się w górę - dawni programiści mieli nieco bardziej bezpośredni kontakt z radzeniem sobie z implikacjami tego faktu niż stos. Wskaźnik do zestawu alternatywnych form implementacji stosu jest również bardzo interesujący.
Ben Zotto,
Czy pamięć wczesnego dnia nie ma sposobu na powiadomienie o jej rozmiarze i musimy to obliczyć ręcznie?
phuclv
1
@ LưuVĩnhPhúc, muszę założyć, że jesteś o pokolenie (lub dwa) za mną. Wciąż pamiętam metodę TRS-80 model 3 do uzyskiwania daty i godziny, aby poprosić użytkownika o to podczas uruchamiania. Posiadanie skanera pamięci do ustawiania górnego limitu pamięci było uważane za najnowocześniejsze w tamtych czasach :-) Czy możesz sobie wyobrazić, co by się stało, gdyby system Windows pytał o czas lub ile masz pamięci przy każdym uruchomieniu?
paxdiablo
1
Rzeczywiście, dokumentacja Zilog Z80 mówi, że część uruchamia się, ustawiając rejestr komputera na 0000h i wykonując. Ustawia tryb przerwania na 0, wyłącza przerwania, a także ustawia rejestry I i R na 0. Następnie zaczyna się wykonywać. O godzinie 0000 rozpoczyna wykonywanie kodu. TEN kod musi zainicjować wskaźnik stosu, zanim będzie mógł wywołać podprogram lub włączyć przerwania. Który sprzedawca sprzedaje Z80, który zachowuje się tak, jak opisujesz?
MikeB
1
Mike, przepraszam, powinienem był wyjaśnić. Kiedy powiedziałem, że procesor skanuje pamięć, nie miałem na myśli, że jest to funkcja samego procesora. W rzeczywistości był sterowany z programu w pamięci ROM. Wyjaśnię.
paxdiablo
21

Jednym z dobrych wyjaśnień, które słyszałem, było to, że niektóre maszyny w przeszłości mogły mieć tylko nieoznaczone przesunięcia, więc chciałbyś, aby stos rósł w dół, abyś mógł uderzać w lokalnych graczy bez utraty dodatkowych instrukcji, aby sfałszować ujemne przesunięcie.

anq
źródło
8

Stanley Mazor (architekt z 4004 i 8080) wyjaśnia, w jaki sposób wybrano kierunek wzrostu stosu dla 8080 (i ostatecznie dla 8086) w „Mikroprocesorach Intel: 8008 do 8086” :

Wskaźnik stosu został wybrany do biegu „w dół” (ze stosem przesuwającym się w kierunku mniejszej ilości pamięci), aby uprościć indeksowanie do stosu z programu użytkownika (indeksowanie dodatnie) i uprościć wyświetlanie zawartości stosu z panelu przedniego.

roolebo
źródło
6

Jednym z możliwych powodów może być to, że upraszcza wyrównanie. Jeśli umieścisz lokalną zmienną na stosie, która musi być umieszczona na 4-bajtowej granicy, możesz po prostu odjąć rozmiar obiektu od wskaźnika stosu, a następnie wyzerować dwa dolne bity, aby uzyskać odpowiednio wyrównany adres. Jeśli stos rośnie w górę, zapewnienie wyrównania staje się nieco trudniejsze.

jalf
źródło
1
Komputery nie odejmują; dodają komplement dwójki. Wszystko, co jest robione przez odejmowanie, tak naprawdę robi się przez dodanie. Rozważmy, że komputery mają sumatory, a nie odejmowanie.
jww
1
@jww - to różnica bez różnicy. Mógłbym równie dobrze twierdzić, że komputery nie dodają, tylko odejmują! Dla celów tej odpowiedzi nie ma to większego znaczenia - ale większość jednostek ALU będzie używać obwodu, który obsługuje zarówno dodawanie, jak i odejmowanie przy tej samej wydajności. Oznacza to, że chociaż A - Bkoncepcyjnie można by to zaimplementować jako A + (-B)(tj. Oddzielny krok negacji dla B), nie jest to w praktyce.
BeeOnRope
@jww Twój chwytak jest zły dla wczesnych komputerów - zajęło trochę czasu, zanim dopełnienie dwóch wygrywało, a dopóki to się nie udało, były komputery używające swojego dopełnienia i znaku i wielkości, a może zamiast tego inne rzeczy. Dzięki tym implementacjom dodawanie w porównaniu z odejmowaniem mogło być korzystne. Wobec braku dodatkowych informacji błędem jest wykluczenie tego jako możliwego czynnika wpływającego na wybór schematu adresowania, taki jak kierunek stosu.
mtraceur
4

IIRC stos rośnie w dół, ponieważ sterta rośnie w górę. Mogło być na odwrót.

Christian V
źródło
5
Sterta rosnąca w górę umożliwia w niektórych przypadkach wydajną ponowną alokację, ale sterta rosnąca w dół prawie nigdy tego nie robi.
Peter Cordes,
@PeterCordes dlaczego?
Yashas
3
@Yashas: ponieważ realloc(3)potrzebuje więcej miejsca po obiekcie, aby po prostu rozszerzyć mapowanie bez kopiowania. Wielokrotne ponowne przydzielanie tego samego obiektu jest możliwe, jeśli następuje po nim dowolna ilość niewykorzystanego miejsca.
Peter Cordes
2

Uważam, że to wyłącznie decyzja projektowa. Nie wszystkie z nich rosną w dół - zobacz ten wątek SO, aby uzyskać dobrą dyskusję na temat kierunku wzrostu stosu na różnych architekturach.

Kaleb Brasee
źródło
1

Myślę, że konwencja rozpoczęła się od IBM 704 i jego niesławnego „rejestru dekrementów”. Współczesna mowa nazwałaby to przesunięciem pola instrukcji, ale chodzi o to, że spadły one w dół , a nie w górę .

luser droog
źródło
1

Jeszcze tylko 2 centy:

Poza wszystkimi wspomnianymi historycznymi przesłankami jestem całkiem pewien, że nie ma powodu, który byłby ważny w przypadku nowoczesnych procesorów. Wszystkie procesory mogą przyjmować podpisane przesunięcia, a maksymalizacja odległości stosu / stosu jest raczej dyskusyjna, odkąd zaczęliśmy zajmować się wieloma wątkami.

Osobiście uważam to za wadę projektu zabezpieczeń. Jeśli, powiedzmy, projektanci architektury x64 odwróciliby kierunek wzrostu stosu, większość przepełnień bufora stosu zostałaby wyeliminowana - co jest dość dużym problemem. (ponieważ struny rosną w górę).

Ofek Shilon
źródło
0

Nie jestem pewien, ale kiedyś programowałem dla VAX / VMS. Wydaje mi się, że jedna część pamięci (sterta?) Rosła, a stos spadał. Kiedy się spotkali, zabrakło ci pamięci.

Jaskółka oknówka
źródło
1
To prawda, ale w takim razie dlaczego sterta rośnie w górę, a nie na odwrót?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
0

Jedną z zalet rosnącego stosu rosnącego w minimalnym systemie wbudowanym jest to, że pojedynczy fragment pamięci RAM może być redundantnie mapowany zarówno na stronę O, jak i stronę 1, umożliwiając przypisanie zerowych zmiennych stron począwszy od 0x000, a stos rośnie w dół od 0x1FF, maksymalizując ilość, którą musiałby wzrosnąć przed nadpisaniem zmiennych.

Jednym z pierwotnych założeń projektowych 6502 było to, że można go było połączyć, na przykład, z 6530, w wyniku czego powstał dwuczipowy system mikrokontrolera z 1 KB pamięci ROM programu, timerem, we / wy i 64 bajtami współdzielonej pamięci RAM między zmiennymi stosu i zerowej strony. Dla porównania, minimalny system wbudowany w tamtych czasach oparty na 8080 lub 6800 składał się z czterech lub pięciu chipów.

Mediolan
źródło