Programmation Assembleur/x86/La pile

Un livre de Wikilivres.
Programmation Assembleur/x86
Modifier ce modèle


La pile est une zone de mémoire permettant de stocker et retrouver rapidement des valeurs pour :

  • Placer des variables locales dans un sous-programme,
  • Sauvegarder l'adresse de retour (fait par les instructions CALL, INT),
  • Transmettre les arguments à un sous-programme.

Fonctionnement[modifier | modifier le wikicode]

Une pile fonctionne à la manière d'une pile d'objets réels :

  • Il est possible d'ajouter une valeur au sommet de la pile (empiler),
  • Il est possible de retirer la valeur située au sommet de la pile (dépiler).

Exemple : soit une pile initialement vide

Empiler A :
Pile        A
Sommet = 1  ^
Index :     1    2    3    4

Empiler B :
Pile        A    B
Sommet = 2       ^
Index :     1    2    3    4

Empiler A :
Pile        A    B    A
Sommet = 3            ^
Index :     1    2    3    4

Dépiler (on obtient A) :
Pile        A    B 
Sommet = 2       ^
Index :     1    2    3    4

Les registres[modifier | modifier le wikicode]

Deux registres sont utilisés pour gérer la pile : SS et SP. Ces deux registres forment le pointeur de pile qui pointe le sommet de la pile en mémoire.

SS (Stack Segment)
Donne le segment mémoire 16K utilisée par la pile.
SP (Stack Pointer)
Donne l'offset dans le segment de la pile du sommet.

Les instructions[modifier | modifier le wikicode]

Empiler[modifier | modifier le wikicode]

L'instruction PUSH permet d'empiler la valeur fournie en argument sur la pile. Plus précisément, cette instruction réalise les opérations suivantes :

  • décrémenter SP du nombre d'octets occupés par la valeur spécifiée,
  • copier la valeur spécifiée à l'emplacement mémoire pointé par SS:SP.

Exemple :

-- SP vaut FFEE
PUSH AX
-- SP vaut FFEC (- 2 octets occupés par AX)

La décrémentation peut paraître surprenante au premier abord. Ce mode de fonctionnement vient du fait que dans le modèle mémoire initial (utilisé par les premiers BIOS et MS-DOS) le tas et la pile se partagent le même segment : le tas partant des adresses basses, et la pile des adresses hautes. Ceci permet d'éviter une limite de tas ou de pile, tout en ayant une limite pour le tas + la pile.

Zone mémoire : [------        ------------]
                TAS →               ← PILE

Le tas est la zone ou sont allouées les variables dynamiques. Dans ce modèle de mémoire, il faut donc faire un compromis entre la pile et le tas : ne pas allouer trop de mémoire sous peine de limiter la pile (récurrence des appels de sous-routines et variables dans la pile), ni allouer trop d'espace dans la pile si beaucoup d'espace mémoire est alloué.

L'instruction spéciale PUSHF (Push Flags) n'a pas d'argument et empile la valeur du registre des indicateurs (EFLAGS).

Il existe également l'instruction PUSHA pour empiler la valeur de tous les registres (Push All).

Dépiler[modifier | modifier le wikicode]

L'instruction POP est l'instruction utilisée pour dépiler une valeur dans le registre ou l'adresse mémoire spécifiée en argument. Cette instruction réalise les opérations suivantes :

  • copier depuis l'emplacement mémoire pointé par SS:SP vers le registre spécifié un nombre d'octets égal à sa taille,
  • incrémenter SP du nombre d'octets copiés.

Exemple :

-- SP vaut FFEC
POP BX
-- SP vaut FFEE

L'instruction spéciale POPF (Pop Flags) n'a pas d'argument explicite et dépile la valeur de la pile vers le registre des indicateurs (EFLAGS).

Il existe également l'instruction POPA pour dépiler la valeur de tous les registres (Pop All) sauvegardés auparavant par l'instruction PUSHA (Push All).