web-dev-qa-db-fra.com

Pourquoi ce risque augmente-t-il vers une diminution des adresses de mémoire?

Je lis dans les manuels que la pile grandit en diminuant l’adresse mémoire; c'est-à-dire, d'une adresse supérieure à une adresse inférieure. C'est peut-être une mauvaise question, mais je n'ai pas bien compris le concept. Peux-tu expliquer?

27
Jestin Joy

Tout d'abord, cela dépend de la plateforme. Dans certaines architectures, la pile est allouée à partir du bas de l'espace d'adressage et se développe vers le haut.

En supposant une architecture comme x86 qui se superpose à partir du haut de l'espace d'adressage, l'idée est assez simple:

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

Pour agrandir la pile, vous diminuez le pointeur de la pile:

===============     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)

Comme vous pouvez le constater, pour agrandir la pile, nous avons diminué le pointeur de pile de 0xEEEE à 0xAAAA, alors que pour agrandir tas, vous devez augmenter le pointeur de tas.

Évidemment, ceci est une simplification de la disposition de la mémoire. L'exécutable réel, la section de données, ... est également chargé en mémoire. En outre, les threads ont leur propre espace de pile.

Vous pouvez demander, pourquoi devrait empiler grandir vers le bas. Eh bien, comme je l’ai déjà dit, certaines architectures font l’inverse, faisant en sorte que tas grossisse et que pile s’agrandisse. Il est logique de placer pile et pile sur les côtés opposés afin d'éviter tout chevauchement et de permettre aux deux zones de se développer librement tant que vous disposez de suffisamment d'espace d'adressage.

Une autre question valable pourrait être: le programme n'est-il pas supposé diminuer/augmenter le pointeur de pile lui-même? Comment une architecture peut-elle imposer un sur l'autre au programmeur? Pourquoi ne dépend-il pas autant du programme que de son architecture? Bien que vous puissiez quasiment combattre l’architecture et écarter d’une manière ou d’une autre votre pile dans la direction opposée, certaines instructions, notamment call et ret, qui modifient directement le pointeur de pile vont prendre une autre direction, ce qui crée un désordre.

47
Mehrdad Afshari

De nos jours, c'est en grande partie parce que cela a été fait depuis longtemps et beaucoup de programmes supposent que c'est ainsi, et il n'y a pas vraiment de raison de le changer.

À l'époque où les dinosaures parcouraient la Terre et que les ordinateurs disposaient de 8 Ko de mémoire, si vous aviez de la chance, il s'agissait d'une importante optimisation de l'espace. Vous placez le bas de la pile en haut de la mémoire, en croissance, et le programme et ses données en bas, avec la zone malloc en croissance. De cette façon, la seule limite sur la taille de la pile était la taille du programme + tas, et vice versa. Si, au contraire, la pile commençait à 4 Ko (par exemple) et grandissait, le segment de mémoire ne pourrait jamais dépasser 4 Ko (moins la taille du programme), même si le programme ne nécessitait que quelques centaines d'octets de pile.

20
zwol

Man CLONE: L'argument child_stack spécifie l'emplacement de la pile utilisée par le processus enfant. Étant donné que le processus enfant et le processus appelant peuvent partager de la mémoire, il n'est pas possible que le processus enfant s'exécute dans la même pile que le processus appelant. Le processus appelant doit donc définir un espace mémoire pour la pile enfant et transmettre un pointeur sur cet espace à clone (). Les piles grandissent vers le bas sur tous les processeurs exécutant Linux (à l'exception des processeurs HP PA). C'est pourquoi child_stack pointe généralement vers l'adresse la plus élevée de l'espace mémoire configuré pour la pile enfant.

0
Asif Bahrainwala