10
votes

Comment le fond de la pile est-il déterminé?

Une pile est un bloc contigu de mémoire contenant des données. Un registre appelé les points de pile pointeur (SP) au sommet de la pile. Le fond de la pile est à une adresse fixe.

Comment est le fond de la pile fixe par le noyau?


0 commentaires

4 Réponses :


1
votes

Cela ferait partie de la mise en œuvre de la pile elle-même. Si vous implémentez une pile dans (par exemple) C, vous pouvez stocker le pointeur de pile et le nombre actuel d'éléments. Ou le pointeur de pile avec la base de la pile, quelque chose comme: xxx

Si vous parlez d'une pile CPU (adresses de retour, etc.), vous pouvez détecter le déroulement de la pile par vertu du fait que vous vous écrasez. Mal.


À titre d'exemple, dans Olden Jours où les processeurs étaient limités à 64K Espace d'adresse, les CPU ont typiquement testé la mémoire jusqu'à ce qu'ils trouvaient le premier octet qui n'a pas lu la même chose que ce qui n'a pas été écrit (dans le processus de démarrage). L'a été le premier octet au-delà de la mémoire physique réelle afin qu'ils définissent SP à un en dessous de cela. Bien sûr, certains (petits nombre de) machines avaient 64k de RAM physique, il suffit de définir SP en haut de l'espace d'adressage.

Le processus de nos jours, dans l'énorme adresse- L'espace, la mémoire virtuelle, les systèmes d'exploitation multi-tâches, est un peu plus compliqué, mais il se résume toujours à (dans la plupart des cas):

  • L'espace d'adresses est attribué pour un processus.
  • SP est défini sur quelque part dans cet espace d'adressage.
  • processus fonctionne.

    À ce moment-là, vous êtes probablement seul autant que le noyau est concerné. Sa responsabilité s'arrête au point où votre code commence à fonctionner autre que la commutation de tâches et à fournir des services comme demandé, mais cela n'a rien à voir avec votre pile. Si votre code de buggy débordne ou insère la pile, c'est votre problème .

    Le noyau peut vérifier votre commutateur de tâche pour voir si vous avez fait quelque chose de mal mais cela n'est pas garanti. Il peut également utiliser une protection de la mémoire matérielle pour détecter un sous-fluide (si la pile est en haut de votre espace d'adresses alloué). Mais encore une fois, cela dépend entièrement du noyau que vous utilisez.


6 commentaires

Qu'est-ce que vous voulez dire par Underflow , j'ai seulement entendu parler de débordement .


Underflow est lorsque vous essayez de faire sauter un élément d'une pile vide. Dans la plupart des systèmes, il impliquera d'accéder à une adresse de mémoire non mappée, ce qui entraînera une défaillance de la segmentation.


Pourquoi un défaut de segmentation est-il nécessaire au lieu de simplement renvoyer un la valeur ?


Parce que, en montage, les opérations pop renvoient ce qu'ils ont sauté, pas un code de résultat.


@Mask, si vous implémentez vous-même une pile vous-même, vous pouvez le faire (renvoyer un indicateur de réussite, donnant la valeur exclus dans une autre manière (comme un pointeur ou une référence) ou renvoyer la valeur, donnant une exception si la pile était vide). Les piles quincailleries ne sont pas si compliquées - elles s'écraseront généralement (la seule raison pour laquelle je mentionne des piles de matériel est parce que vous avez utilisé le travail de "noyau" magique). Stacks de logiciels que vous pouvez faire aussi sûr que vous le souhaitez.


"Alors ils ont défini SP à un en dessous de ça." ... à moins qu'ils n'utilisaient des piles de prérérètes (comme l'architecture M68K), auquel cas omettez "un ci-dessous".



7
votes

J'ai tapé une réponse plus longue, mais elle se dirigea, alors voici une plus courte ...

Lorsqu'un processus est démarré, il faut une pile dans le but de stocker des valeurs temporaires (c'est-à-dire une allocation automatique) ou des cadres de pile lorsque des fonctions sont appelées. La mémoire de cette pile doit venir de quelque part.

Ainsi, ce que le système d'exploitation crée une mappage dans la mémoire virtuelle pour la pile et attribue le pointeur de pile à l'adresse haute de ce bloc. Dans une pile de prérérètes, où le pointeur de pile est décrémenté avant la déséroférance, le pointeur de pile initial est en réalité l'adresse au-delà de la dernière adresse de l'espace mappé.

Lorsque le processus tente de mettre quelque chose sur la pile, il se traduit par un accès à cette région de mémoire, qui n'a pas de bélier physique mappée. Cela provoque une défaillance de la page, ce qui permet à l'OS frappe la page de RAM le moins utilisée (ou à proximité de celle-ci) dans le lecteur de swap ou sur le fichier de page, et réaffectant la page de RAM physique à la page de pile d'accès. Maintenant qu'il existe une RAM physique, le système d'exploitation et le processus se poursuit, mettant les données poussées dans la mémoire de la pile.

Alors, que se passe-t-il si vous allez tout sur la pile, puis essayez de faire la population? Ce dernier POP, où le pointeur de pile est à sa valeur initiale, donne un accès à une adresse de mémoire virtuelle pas mappée sur la pile. Cela provoque une défaillance de la segmentation, ce qui signifie que le processus a essayé d'accéder à la mémoire qu'elle n'a jamais été allouée. Le système d'exploitation répond en terminant le processus et en nettoyant ce qu'il peut.

Pourquoi ne pas mapper une page après la fin de la pile? Parce que cela entraînerait la lecture de RAM non initialisée, qui contiendra tout ce qui est utilisé pour utiliser cette page de RAM physique. Il y a simplement aucun moyen cela peut produire un programme correctement fonctionnel (ne rien dire de la manière dont il s'agit d'un risque de sécurité énorme), il est donc toujours préférable de tuer le programme.


6 commentaires

Bonne réponse. J'aimerais voir ce que la version longue est. :-)


La mémoire virtuelle est essentiellement un disque dur, ce qui est très lent, alors je pense que cela n'est utilisé que lorsque le RAM n'est pas suffisant, non?


@Mask, la mémoire virtuelle est pas un disque dur. C'est une déconnexion entre l'espace d'adressage que votre processus voit et la mémoire physique réelle. Vous pouvez avoir une mémoire virtuelle sans échange ni pagination sur disque dans ce que vous n'avez pas besoin de vous inquiéter du code indépendant de la position - Vous supposez simplement que votre code fonctionnera à la même adresse mémoire, quel que soit son emplacement physique. Vous pouvez également avoir une pagination sans mémoire virtuelle également si plusieurs processus souhaitaient utiliser les mêmes adresses.


@Sam: la version longue rencontrée dans la manière dont le noyau met en place STDIN / STDOUT / STDROUT pour vous, cartographies dans l'exécutable à un autre morceau de mémoire (il n'est donc pas nécessaire de charger du code tant qu'il n'en a pas vraiment besoin), et enfin des ensembles le tas. (Le fait que le tas commence à partir de la mémoire basse et pousse à la hausse explique comment utiliser trop de tas peut corrompre la pile.)


@Mask: "Mémoire virtuelle" est un terme qui fait référence à la capacité d'un ordinateur assez complexe pour maintenir des espaces d'adresse distincts pour les processus pouvant ou non avoir aucun rapport avec les adresses physiques. En d'autres termes, si vous avez un système d'exploitation de mémoire virtuelle et que votre processus a une adresse (c'est-à-dire un pointeur), cette adresse peut être différente de l'adresse présentée aux puces RAM. De plus, cette adresse sera probablement pas donner un sens à un autre processus. C'est pourquoi vous devez aller au système d'exploitation et mendier pour pouvoir partager la mémoire entre les processus.


@Mask: Ne confondez pas le terme "Mémoire virtuelle" avec "Swap" (qui est l'endroit où la mémoire qui n'est pas dans la RAM physique est stockée) ou "adresses virtuelles" (qui sont les adresses / les pointeurs que votre processus gagne de Malloc () etc.).



1
votes

Je suppose que vous voulez dire "fixé dans l'espace mémoire du processus" et non "fixé dans la mémoire globale". Vous pouvez regarder où le fond de la pile est dans n'importe quel système de Linux récent en recherchant une ligne comme xxx

dans la sortie de CAT / PROC / / MAPS < / code>. Dans ce cas, le bas de la pile est, dans ce cas, à 0xbffeb000 . Dans mon système, tous les bas de la pile semblent tomber dans l'un des bffca000 bffcb000 bffdd000 bffe0000 bffe4000 bffe6000 bffeb000 (après la boucle à ~ 200 procédés).

Je suppose que ces valeurs sont attribuées au-delà du noyau, partout où les processus sont créés pour la première fois.


3 commentaires

Je pense que les adresses de pile sont randomisées, certaines pour rendre plus difficile pour les exploits de dépassement de pile pour fonctionner.


@Mike je me souviens de sorte que la randomisation se passe dans des adresses mappées en mémoire, mais si les piles sont en effet randomisées, 7 valeurs de 200 échantillons constituent une très mauvaise randomisation :-)


Maintenant que vous le mentionnez, cela ressemble plus à quelque chose d'autre qui se caractérise dans l'espace plus près de C0000000 et qui a une taille incohérente (54, 53, 35, 32, 28, 26, ou 21K pages).



0
votes

En fait, il y a quelque chose après le bas de la pile. Après la pile, il y a les éléments du tableau ARGV, puis les éléments du tableau ENV. Ensuite, c'est une barrière, puis le code libc.


0 commentaires