274 votes

Ce qui est exactement le pointeur de base et le pointeur de pile ? Pour ce ils pointent ?

À l'aide de cet exemple venant de wikipedia, dans lequel DrawSquare() appelle DrawLine(),

alt text

quelqu'un pourrait-il m'expliquer ce que l'ebp et esp sont dans ce contexte?

De ce que je vois, je dirais que le pointeur de pile points toujours en haut de la pile, et le pointeur de la base au début de la fonction actuelle? Ou quoi?

Merci

edit: je veux dire dans le contexte de programmes de windows

edit2: Et comment est-eip travail, trop?

edit3: j'ai le code suivant à partir de MSVC++:

var_C= dword ptr -0Ch
var_8= dword ptr -8
var_4= dword ptr -4
hInstance= dword ptr  8
hPrevInstance= dword ptr  0Ch
lpCmdLine= dword ptr  10h
nShowCmd= dword ptr  14h

Tous d'entre eux semblent être dwords, prenant ainsi de 4 octets chacun. Donc, je peux voir il y a un écart de hInstance var_4 de 4 octets. Quels sont-ils? Je suppose que c'est l'adresse de retour, comme on peut le voir dans la page wikipedia de l'image?

Michael réponse:

var_C= dword ptr -0Ch

var_8= dword ptr -8

var_4= dword ptr -4

savedFramePointer= dword ptr 0

adresse de retour= dword ptr 4

hInstance= dword ptr 8h

PrevInstance= dword ptr 0C

hlpCmdLine= dword ptr 10h

nShowCmd= dword ptr 14h

C'est parce que le flux de l'appel de la fonction est:

* Push parameters (hInstance, etc.)
* Call function, which pushes return address
* Push ebp
* Allocate space for locals

Ma question (enfin, j'espère!) maintenant, quelle est exactement ce qui se passe à partir de l'instant où je mets les arguments de la fonction, je tiens à appeler jusqu'à la fin du prologue? Je veux savoir comment l'ebp, esp évoluer au cours de ces moments(j'ai déjà compris comment le prologue de travaux, je veux juste savoir ce qui se passe après j'ai poussé les arguments sur la pile et avant le prologue).

272voto

Michael Points 34110

esp est comme tu le dis c'est, du haut de la pile.

ebp est généralement fixé à l'esp au début de la fonction. Les variables locales sont accessibles par la soustraction d'un décalage constant de ebp. Tous x86 conventions d'appel de définir ebp comme étant conservée à travers les appels de fonction. ebp lui-même en fait des points de l'image précédente de la base de pointeur, ce qui permet à la pile de la marche dans un débogueur et l'affichage d'autres cadres de variables locales à travailler.

La plupart de fonction prologs ressembler à quelque chose comme:

push ebp      ; Preserve current frame pointer
mov ebp, esp  ; Create new frame pointer pointing to current stack top
sub esp, 20   ; allocate 20 bytes worth of locals on stack.

Puis, plus tard dans la fonction, vous pouvez avoir un code comme (en supposant à la fois les variables locales sont de 4 octets)

mov [ebp-4], eax    ; Store eax in first local
mov ebx, [ebp - 8]  ; Load ebx from second local

FPO ou pointeur de l'image de l'omission d'optimisation que vous pouvez activer réellement éliminer le présent et l'utilisation ebp comme un autre registre et l'accès des habitants directement à partir de l'esp, mais cela permet de déboguer un peu plus difficile car le débogueur ne peut plus accéder directement à la pile d'images de plus tôt les appels de fonction.

EDIT:

Pour la mise à jour de votre question, l'absence de deux entrées dans la pile sont:

var_C = dword ptr -0Ch
var_8 = dword ptr -8
var_4 = dword ptr -4
*savedFramePointer = dword ptr 0*
*return address = dword ptr 4*
hInstance = dword ptr  8h
PrevInstance = dword ptr  0C
hlpCmdLine = dword ptr  10h
nShowCmd = dword ptr  14h

C'est parce que le flux de l'appel de la fonction est:

  • Pousser paramètres (hInstance, etc.)
  • La fonction d'appel, qui pousse l'adresse de retour
  • Push ebp
  • Allouer de l'espace pour les habitants

141voto

David R Tribble Points 4813

L'ESP est le pointeur de pile actuel, qui va changer tout le temps d'une parole ou d'adresse est poussé ou sauté sur/off en dehors de la pile. EBP est un moyen plus pratique pour le compilateur pour garder la trace d'une fonction, les paramètres et les variables locales que l'aide de l'ESP directement.

Généralement (et cela peut varier d'un compilateur de compilateur), tous les arguments d'une fonction appelée est poussé sur la pile (généralement dans l'ordre inverse dans lequel elles sont déclarées dans le prototype de fonction, mais cela varie). Alors la fonction est appelée, ce qui pousse l'adresse de retour (EIP) sur la pile.

Dès l'entrée dans la fonction, l'ancien EBP valeur est poussé sur la pile et EBP est définie à la valeur de ESP. Ensuite, l'ESP est décrémenté (parce que la pile grandit vers le bas dans la mémoire) pour allouer de l'espace pour la fonction de variables locales et temporaires. À partir de ce point, lors de l'exécution de la fonction, les arguments de la fonction sont situés sur la pile au positif décalages de EBP (parce qu'ils ont été poussés avant l'appel de la fonction), et les variables locales sont situés à des décalages négatifs de EBP (parce qu'ils ont été alloués sur la pile après l'entrée de la fonction). C'est pourquoi l'EBP est appelé le pointeur de l'image, car il pointe vers le centre de l' appel de la fonction cadre.

Lors de la sortie, toutes les fonctions a à faire est de mettre en ESP à la valeur de EBP, et puis le vieux EBP valeur est sortie, alors la fonction renvoie (popping l'adresse de retour dans EIP).

18voto

Robert Cartaino Points 12173

Vous l'avez droit. Le pointeur de pile pointe vers le premier élément de la pile et de la base d'un pointeur sur le "précédent" en haut de la pile avant l'appel de la fonction.

Lorsque vous appelez une fonction, toute variable locale sera stockée sur la pile et le pointeur de pile sera incrémenté. Lorsque vous êtes de retour de la fonction, toutes les variables locales dans la pile hors de portée. Vous le faire en mettant le pointeur de pile de retour à la base pointeur (qui a été le "précédent" top avant l'appel de fonction).

Faire de l'allocation de la mémoire de cette façon est très, très rapide et efficace.

8voto

wigy Points 504

EDIT: Pour une meilleure description, voir x86/Démontage des Fonctions et une Pile d'Images dans un WikiBook sur x86 assemblée. J'essaie d'ajouter quelques infos qui pourraient vous intéresser dans l'aide de Visual Studio.

Le stockage de l'appelant EBP comme la première variable locale est appelée une pile standard de trame, et cela peut être utilisé pour presque toutes les conventions d'appel sur Windows. Il existe des différences de savoir si l'appelant ou de l'appelé libère les paramètres passés, et dont les paramètres sont passés dans les registres, mais ce sont orthogonales à la norme frame de pile problème.

Parlant de programmes de Windows, vous pourriez probablement utiliser Visual Studio pour compiler votre code C++. Sachez que Microsoft utilise une optimisation appelé Pointeur de l'Image d'une Omission, qu'il est presque impossible de faire marcher la pile sans l'aide de la dbghlp bibliothèque et le fichier PDB pour l'exécutable.

Ce Pointeur de Cadre Omission signifie que le compilateur ne pas stocker l'ancienne EBP sur un endroit standard et utilise EBP pour autre chose, donc vous avez du mal à trouver de l'appelant EIP sans savoir combien d'espace les variables locales ont besoin pour une fonction donnée. Bien sûr, Microsoft fournit une API qui permet de faire de la pile-promenades, même dans ce cas, mais la recherche de la table des symboles de la base de données dans des fichiers PDB prend trop de temps pour certains cas d'utilisation.

Pour éviter la FPO dans vos unités de compilation, vous devez éviter d'utiliser /O2 ou besoin d'ajouter de manière explicite /Oy - à la compilation C++ drapeaux dans vos projets. Vous avez probablement link contre le C ou C++ qui utilise la FPO dans la configuration de Version, de sorte que vous aurez du mal à faire de la pile marche sans le dbghlp.dll.

6voto

jmucchiello Points 10521

Tout d'abord, le pointeur de pile vers le bas de la pile depuis x86 piles de construire de hautes valeurs d'adresse à la baisse des valeurs d'adresse. Le pointeur de pile est le point où le prochain appel à pousser (ou appel) aura lieu la prochaine valeur. C'est l'équivalent du C/C++ déclaration:

 // push eax
 --*esp = eax
 // pop eax
 eax = *esp++;

 // a function call, in this case, the caller must clean up the function parameters
 move eax,some value
 push eax
 call some address  // this pushes the next value of the instruction pointer onto the
                    // stack and changes the instruction pointer to "some address"
 add esp,4 // remove eax from the stack

 // a function
 push ebp // save the old stack frame
 move ebp, esp
 ... // do stuff
 pop ebp  // restore the old stack frame
 ret

Le pointeur de la base est en haut de l'image actuelle. ebp généralement des points à votre adresse de retour. ebp+4 points pour le premier paramètre de la fonction (ou le ce de la valeur d'une méthode de classe). ebp-4 points pour la première variable locale à la fonction, généralement de l'ancienne valeur de ebp de sorte que vous pouvez restaurer l'état de la pointeur de l'image.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X