Pourquoi les piles poussent-elles généralement vers le bas?

95

Je sais que dans les architectures que je connais personnellement (x86, 6502, etc.), la pile croît généralement vers le bas (c'est-à-dire que chaque élément poussé sur la pile entraîne un SP décrémenté, pas incrémenté).

Je me demande quelle est la justification historique de cela. Je sais que dans un espace d'adressage unifié, il est pratique de démarrer la pile à l'extrémité opposée du segment de données (par exemple), donc il n'y a qu'un problème si les deux côtés se heurtent au milieu. Mais pourquoi la pile obtient-elle traditionnellement la partie supérieure? D'autant plus que c'est l'opposé du modèle «conceptuel»?

(Et notez que dans l'architecture 6502, la pile se développe également vers le bas, même si elle est limitée à une seule page de 256 octets, et ce choix de direction semble arbitraire.)

Ben Zotto
la source

Réponses:

52

Quant à la justification historique, je ne peux pas dire avec certitude (parce que je ne les ai pas conçues). Mes pensées à ce sujet sont que les premiers processeurs ont mis leur compteur de programme d'origine à 0 et que c'était un désir naturel de démarrer la pile à l'autre bout et de croître vers le bas, car leur code croît naturellement vers le haut.

En passant, notez que ce réglage du compteur de programme à 0 lors de la réinitialisation n'est pas le cas pour tous les premiers processeurs. Par exemple, le Motorola 6809 récupère le compteur de programme à partir des adresses0xfffe/f afin que vous puissiez commencer à fonctionner à un emplacement arbitraire, en fonction de ce qui a été fourni à cette adresse (généralement, mais en aucun cas limité à, ROM).

L'une des premières choses que certains systèmes historiques feraient serait d'analyser la mémoire du haut jusqu'à ce qu'il trouve un emplacement qui lirait la même valeur écrite, de sorte qu'il connaisse la RAM réelle installée (par exemple, un z80 avec un espace d'adressage de 64 Ko. n'avait pas nécessairement 64K ou RAM, en fait 64K aurait été énorme à mes débuts). Une fois qu'il a trouvé l'adresse réelle supérieure, il définirait le pointeur de pile de manière appropriée et pourrait alors commencer à appeler des sous-programmes. Cette analyse serait généralement effectuée par le CPU exécutant le code dans la ROM dans le cadre du démarrage.

En ce qui concerne la croissance des piles, toutes ne poussent pas vers le bas, voir cette réponse pour plus de détails.

paxdiablo
la source
1
J'aime l'histoire de la stratégie de détection de la RAM Z80. Cela a du sens que les segments de texte soient disposés de plus en plus vers le haut - les programmeurs d'autrefois avaient un contact un peu plus direct pour gérer les implications de cela que la pile.Merci paxdiablo. Le pointeur vers l'ensemble des formes alternatives d'implémentations de pile est également très intéressant.
Ben Zotto
La mémoire précoce n'a-t-elle pas un moyen de notifier sa taille et nous devons la calculer manuellement?
phuclv
1
@ LưuVĩnhPhúc, je dois supposer que vous êtes une génération (ou deux) derrière moi. Je me souviens encore de la méthode TRS-80 modèle 3 pour obtenir la date et l'heure étant de la demander à l'utilisateur au moment du démarrage. Avoir un scanner de mémoire pour définir la limite supérieure de la mémoire était considéré comme l'état de l'art à l'époque :-) Pouvez-vous imaginer ce qui se passerait si Windows vous demandait l'heure ou la quantité de mémoire dont vous disposiez à chaque démarrage?
paxdiablo
1
En effet, la documentation du Zilog Z80 indique que la pièce démarre en définissant le registre du PC sur 0000h et en s'exécutant. Il définit le mode d'interruption sur 0, désactive les interruptions et définit également les registres I et R sur 0. Après cela, il commence à s'exécuter. À 0000h, il commence à exécuter le code. CE code doit initialiser le pointeur de pile avant de pouvoir appeler un sous-programme ou activer des interruptions. Quel fournisseur vend un Z80 qui se comporte comme vous le décrivez?
MikeB
1
Mike, désolé, j'aurais dû être plus clair. Quand j'ai dit que la mémoire était analysée par le processeur, je ne voulais pas dire que c'était une caractéristique du processeur lui-même. Il était en fait contrôlé à partir d'un programme en ROM. Je vais clarifier.
paxdiablo
21

Une bonne explication que j'ai entendue était que certaines machines dans le passé ne pouvaient avoir que des décalages non signés, vous voudriez donc que la pile augmente vers le bas afin de pouvoir frapper vos habitants sans avoir à perdre l'instruction supplémentaire pour simuler un décalage négatif.

anq
la source
7

Stanley Mazor (architecte 4004 et 8080) explique comment la direction de croissance de la pile a été choisie pour 8080 (et finalement pour 8086) dans "Intel Microprocessors: 8008 to 8086" :

Le pointeur de pile a été choisi pour fonctionner en "descente" (avec la pile avançant vers la mémoire inférieure) pour simplifier l'indexation dans la pile à partir du programme de l'utilisateur (indexation positive) et pour simplifier l'affichage du contenu de la pile à partir d'un panneau avant.

roolebo
la source
6

Une raison possible pourrait être que cela simplifie l'alignement. Si vous placez une variable locale sur la pile qui doit être placée sur une limite de 4 octets, vous pouvez simplement soustraire la taille de l'objet du pointeur de pile, puis remettre à zéro les deux bits inférieurs pour obtenir une adresse correctement alignée. Si la pile se développe vers le haut, assurer l'alignement devient un peu plus délicat.

jalf
la source
1
Les ordinateurs ne soustraient pas; ils ajoutent le compliment de 2. Tout ce qui est fait en soustrayant est vraiment fait en ajoutant. Considérez que les ordinateurs ont des additionneurs, pas des soustracteurs.
jww
1
@jww - c'est une distinction sans différence. Je pourrais bien prétendre que les ordinateurs n'ajoutent pas qu'ils ne font que soustraire! Pour les besoins de cette réponse, cela n'a pas vraiment d'importance - mais la plupart des ALU utiliseront un circuit qui prend en charge à la fois l'addition et la soustraction avec les mêmes performances. Autrement dit, bien que cela A - Bpuisse être mis en œuvre conceptuellement comme A + (-B)(c'est-à-dire une étape de négation distincte pour B), ce n'est pas dans la pratique.
BeeOnRope
@jww Votre choix est faux pour les premiers ordinateurs - il a fallu un certain temps pour que le complément à deux l'emporte, et jusqu'à ce que ce soit le cas, il y avait des ordinateurs utilisant son complément et son signe et sa grandeur et peut-être d'autres choses à la place. Avec ces implémentations, il peut bien y avoir eu un avantage à ajouter plutôt qu'à soustraire. Donc, en l'absence d'informations supplémentaires, il est erroné d'exclure cela comme un facteur possible influençant les choix de schéma d'adressage comme la direction de la pile.
mtraceur le
4

IIRC la pile se développe vers le bas parce que le tas se développe vers le haut. Cela aurait pu être l'inverse.

Christian V
la source
5
Un tas croissant vers le haut permet une réallocation efficace dans certains cas, mais un tas croissant vers le bas ne le fait pratiquement jamais.
Peter Cordes
@PeterCordes pourquoi?
Yashas
3
@Yashas: parce qu'il realloc(3)faut plus d'espace après un objet pour simplement étendre le mappage sans copier. Une réallocation répétée du même objet est possible lorsqu'elle est suivie d'une quantité arbitraire d'espace inutilisé.
Peter Cordes
2

Je pense que c'est purement une décision de conception. Tous ne poussent pas vers le bas - voir ce fil de discussion SO pour une bonne discussion sur la direction de la croissance de la pile sur différentes architectures.

Kaleb Brasee
la source
1

Je crois que la convention a commencé avec l'IBM 704 et son infâme «registre de décrémentation». Le discours moderne appellerait cela un champ décalé de l'instruction, mais le fait est qu'ils sont descendus , pas montés .

Luser droog
la source
1

Juste 2c de plus:

Au-delà de toutes les raisons historiques mentionnées, je suis tout à fait certain qu'il n'y a aucune raison valable dans les processeurs modernes. Tous les processeurs peuvent prendre des décalages signés, et maximiser la distance tas / pile est plutôt inutile depuis que nous avons commencé à traiter plusieurs threads.

Personnellement, je considère cela comme un défaut de conception de la sécurité. Si, par exemple, les concepteurs de l'architecture x64 avaient inversé la direction de la croissance de la pile, la plupart des débordements de tampon de pile auraient été éliminés - ce qui est un gros problème. (puisque les cordes poussent vers le haut).

Ofek Shilon
la source
0

Je ne suis pas sûr mais j'ai fait de la programmation pour le VAX / VMS à l'époque. Il me semble me souvenir d'une partie de la mémoire (le tas ??) qui monte et la pile descend. Lorsque les deux se sont rencontrés, vous étiez à court de mémoire.

Martin
la source
1
C'est vrai, mais alors pourquoi le tas se développe-t-il vers le haut et non l'inverse?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
0

L'un des avantages de la croissance décroissante de la pile dans un système embarqué minimal est qu'un seul morceau de RAM peut être mappé de manière redondante à la fois sur la page O et la page 1, ce qui permet d'attribuer zéro variable de page à partir de 0x000 et la pile croît vers le bas à partir de 0x1FF, maximisant ainsi le montant qu'il faudrait augmenter avant d'écraser les variables.

L'un des objectifs de conception d'origine du 6502 était qu'il puisse être combiné avec, par exemple, un 6530, ce qui se traduisait par un système de microcontrôleur à deux puces avec 1 Ko de programme ROM, une minuterie, des E / S et 64 octets de RAM partagés entre les variables de pile et de page zéro. Par comparaison, le système embarqué minimal de l'époque basé sur un 8080 ou un 6800 serait de quatre ou cinq puces.

Milan
la source