Mémoire - ségmentation   Version imprimable de cet article Enregistrer au format PDF

Lorsque un programme est lancé, une plage mémoire est réservée pour l’éxécution du programme. Cette mémoire du programme est divisée en 5 segment : text, data, bss, heap et stack. Le plus communément connu est sans conteste le segment stack, en français, la pile.


par S3cur3D

Chaque segment se voit attribuer une portion spéciale de la mémoire et est mis en place pour remplir une fonction différente :

Le segment text : ce segment est aussi appellé le segment code. Il sert à stocker les instructions machine du programme. Au démarrage du programme, EIP pointe vers la première instruction de ce segment. Ensuite, le processeur suit la boucle d’éxécution suivante :

  1. On lit l’instruction vers laquelle EIP pointe
  2. On ajoute la longueur de l’instruction à EIP (passer à l’instruction suivante)
  3. On éxécute l’instruction lue à la première étape
  4. On recommence

Il se peut que l’instruction lue en 3 soit une instruction de type call ou jump qui vont changer l’ordre d’éxécution prédéfini (mettre EIP à une autre adresse définie). Ceci n’affecte en rien le bon déroulement des opérations, car le segment text est prévu pour une éxécution non-linéaire des instructions.
Bien sûr, le droit d’écriture est désactivé sur cette portion de mémoire pour que les instructions ne soient pas changées. Si une modification est apportée, un message avertissant que quelque chose de mauvais est arrivé apparaît et le programme est interrompu. Si le même programme est lancé plusieurs fois, le segment text sera partagé entre les programmes car ce qui est dans ce segment est fixe et ne peut être modifié.

- Les segments data et bss sont utilisés pour stocker les variables globales et statiques du programme. Le segment data est rempli avec les variables globales initialisées au lancement du programme, les chaînes de caractères et les constantes globales. Le bss est rempli avec le reste des variables globales et statiques (non-initialisées). Ces segments peuvent être modifiés mais sont de taille constante (puisqu’ils n’admettent pas de variables dynamiques).

- Le segment heap est utilisé pour toutes les autres variables du programme. Cette fois, des variables pouvant être dynamiques, le segment heap ne peut pas être de taille fixe (sa taille s’adapte au long du programme). Le heap grandit vers les adresses mémoire plus grandes.

- La pile (stack) est aussi de taille variable et est utilisée comme un bloc-note temporaire pendant les appels de fonctions. Quand un programme appelle une fonction, les variables passées à la fonction et les variables de la fonction sont ajoutées à la pile. De plus, EIP doit changer de position dans le text puisqu’il doit pointer vers le code de la fonction. La position où EIP doit retourner après l’éxécution de la fonction est donc également mémorisée.
En informatique générale, le terme "pile" définit une structure de données utilisée fréquemment. Elle peut se modéliser par une pile d’assiette. On dit ce type de structure LIFO ou FILO (first in, last out), à savoir que le premier élément rentré dans la pile sera le dernier à en sortir. Comme dans un empilement d’assiettes, il faut d’abord enlever la dernière assiette posée pour avoir accès à la deuxième qui était en-dessous. Empiler un objet s’appelle le pushing et enlever s’appelle le popping.

Comme son nom l’implique, le segment stack a une structure de pile. Le registre ESP sert en fait à toujours connaître l’emplacement du haut de la pile, de la dernière assiette posée. Bien sûr, la pile ne peut pas non plus avoir une taile fixe. Contrairement au heap, la pile grandit dans le sens des adresses décroissantes.

Quand une fonction est appellée, on push les données précisées ci-dessus dans la pile. Toutes ces données ajoutées d’un coup forment ce qu’on appelle stack frame, ou bloc de pile. La pile est au final formée d’un ensemble de blocs. Le registre EBP, appellé aussi FP (frame pointer) ou LBP (local base pointer), sert à référencer les différentes variables de chaque bloc. On accède aux différentes variables en additionnant ou en soustrayant d’EBP. Les deux premières variables ajoutées à un bloc, après les arguments sont nécessaires au bon déroulement du programme : le SFP, saved frame pointer garde en mémoire la position antérieure (et ultérieure, après le popping) de l’EBP, et le RA, return address, le pointeur vers l’adresse de retour (la prochaine valeur de l’EIP, donc la prochaine instruction après l’appel de la fonction).
Tout ceci peut paraître bien théorique et flou, c’est pourquoi nous avons décidé de consacrer une partie à un exemple complet pour bien illustrer la segmentation et le stockage des variables.

Documentations publiées dans cette rubrique Documentations publiées dans cette rubrique