当前位置:网站首页>Cadre de pile de fonctions schématiques - création et destruction de fonctions

Cadre de pile de fonctions schématiques - création et destruction de fonctions

2021-10-14 05:34:50 Aaronskr

**Avant le début de l'article,Je voudrais vous poser quelques questions,Voyez si vous pouvez répondre à quelques,Après avoir lu cet article,Vous pouvez répondre à quelques autres?

  • Comment les variables locales sont - elles créées??
  • Pourquoi les valeurs des variables locales sont - elles aléatoires?
  • Comment la fonction passe - t - elle les paramètres?Quel est l'ordre de transmission des paramètres?
  • Quelle est la relation entre le paramètre formel et le paramètre réel??
  • Comment faire un appel de fonction?
  • Comment revenir après un appel de fonction?

Préface

Fonctions étudiées: Une fonction d'addition.

Raisons:Les fonctions d'addition sont relativement simples,La logique de mise en œuvre est relativement simple,La création et la destruction de cadres de pile de fonctions peuvent être observées plus clairement,Au lieu de consacrer plus d'efforts à l'étude de fonctions complexes.

#include <stdio.h>

int Add(int x, int y)
{
    
	int z = 0;
	z = x + y;
	return z;
}

int main()
{
    
	int a = 10;
	int b = 20;
	int c = 0;

	c = Add(a, b);
	printf("%d\n", c);

	return 0;
}

Compilateur utilisé : VS2013.

Raisons:Le traitement d'encapsulation du nouveau compilateur sur l'allocation de cadre de pile est parfait,Il n'est pas facile de voir les étapes spécifiques à l'intérieur de l'étude,Les versions inférieures du compilateur sont plus faciles à apprendre.
VS2013

Méthodes de recherche : Illustration.

Raisons: Cet article sera dessiné 、La capture d'écran est illustrée par une explication textuelle,L'attribution des cadres de pile de fonctions peut être comprise plus intuitivement.
Outils de dessin

Le concept de cadre de pile

Le cadre de pile est défini comme La partie de l'espace de pile allouée individuellement par un appel de fonction. Par exemple,,Quand un programme en cours d'exécution appelle une autre fonction,On va entrer dans un nouveau cadre de pile,Le cadre de pile de la fonction originale est appelé le cadre de l'appelant, Le nouveau cadre de pile est appelé le cadre courant . Le cadre courant se contracte complètement après l'exécution de la fonction appelée, Retour au cadre de l'appelant .

Travaux préparatoires

  1. Modifier le code dans le compilateur.

 Édition du texte du Code

  1. Démarrer le débogage et appuyer sur le bouton droit de la souris.(Appuyez surF10)

 Cliquez pour aller au démontage

  1. Aller au démontage.
    Désassemblage

mainCréation et initialisation de cadres de pile de fonctions

mainFonction appelée

Nous devons d'abord être clairs,main()C'est ce qu'on appelle la fonction principale,Il doit être appelé par d'autres fonctions.

  1. Commençons par ouvrir la fenêtre de la pile d'appels dans l'état de débogage.
     Ouvre la fenêtre de la pile d'appels

Comme indiqué ci - dessous:

 Fenêtre de la pile d'appels

  1. Ensuite, on continue à appuyer. F10Mise en service, Jusqu'à la fonction principale return 0Retour, L'interface suivante apparaît .

main Fonction appelée

Retourner vers le haut pour trouver l'appel main() Fonction de la fonction .

Appelezmain Fonction de la fonction
C'est - à - diremain()La fonction est en fait appelée__tmainCRTStartup Appelé par la fonction .


mainOuverture du cadre de pile de fonctions

Nous savons que,L'ouverture des fonctions et des variables locales se fait sur la pile,Et l'habitude d'utiliser la pile est d'utiliser d'abord l'adresse haute, Utiliser une adresse basse après .

Supposons que l'espace de pile soit comme suit: :

Espace de pile

Nous savons quemainLa fonction est également appelée par d'autres fonctions,Donc il y a en fait un compilateur sur la pile pour__tmainCRTStartup Espace ouvert par la fonction , Soyez clair. .

Ensuite, regardons les instructions d'assemblage dans le démontage:

Instructions d'assemblage

Cette partie de l'instruction d'assemblage est en fait justemainLe cadre de pile de la fonction s'ouvre.

Voici un aperçu de ce que vous ne connaissez pas dans la directive:

Registres:ebp,esp,ebx,esi,edi,ecx,eaxAttendez un peu!.

Parmi eux, nous devons nous concentrer sur la fonction de plusieurs registres.

Tenir un registre des cadres de pile de fonctions:

  1. esp - Un registre qui contient l'adresse qui pointe vers le Haut de la pile.
  2. ebp - Un registre qui contient l'adresse au bas de la pile.

Initialiser le registre de la valeur de la fonction:

  1. edi - Pour stocker l'adresse à partir de laquelle l'initialisation a commencé.
  2. ecx - Nombre d'éléments d'initialisation utilisés pour stocker.
  3. eax - Pour stocker le contenu de ce qui va initialiser.

Voici d'abord ce qui suit: main Cas de pile avant la fonction :

__tmainCRTStartupCadre de pile de fonctions

Voici le compilateur pour __tmainCRTStartupCadre de pile de fonctions ouvert par la fonction,Je vois.,ebp Registre pointant vers le bas de la pile ,esp Registre pointant vers le Haut de la pile , Pour maintenir __tmainCRTStartup Cadre de pile de fonctions pour les fonctions .

Nous allons analyser mainOpération d'instruction d'assemblage pour la fonction:
Instructions d'assemblage

push        ebp

Les doigts.ebpValeur dans le registre pour l'opération Stack(push).

C'est - à - dire que le compilateur est déjà __tmainCRTStartupLa fonction ouvre le cadre de pile sur lequel la pile est pressée.

Opération Stack

Parce queesp Est un registre pointant vers le Haut de la pile , Donc après chaque pile espLa position indiquée dans le Registre s'élève, Sinon, si elle est exécutée pop Opération pop - up ,espLa position indiquée dans le registre est abaissée.

esp Position ascendante

En ce moment__tmainCRTStartupLe cadre de pile de fonctions de la fonction augmente également.

 Augmentation du cadre de pile

Action suivante .

Instructions d'assemblage

mov            ebp,esp

Les instructions pour cette opération sont les suivantes: espValeur attribuée àebp.

C'est - à - dire, JeanespL'adresse du magasin est assignée àebp,AlorsebpL'emplacement indiqué changera.

ebp Changement de position
En ce momentebpEtesp Au même endroit. .

Mais attention.:

  1. En ce momentebpEtesp Pas de maintenance __tmainCRTStartupFonction,Mais ça ne veut pas dire que son cadre de pile de fonctions a été détruit,Parce que l'utilisation de l'espace de pile ne peut détruire que les adresses basses, Détruire à nouveau l'adresse élevée .
  2. L'avenirmainAprès le retour de la fonction,espRegistres etebpLe Registre doit encore être maintenu__tmainCRTStartupFonction, Voici la première directive pushDeebpc L'opération est la sonde ,InmainLa fonction renvoie une valeur et exécutepopC'estebpFonctionnement,Allez - y.ebpLe registre rebondit à l'endroit où il a été stocké,C'est - à - dire__tmainCRTStartupBase de pile de la fonction.

Prochaine action :

Instructions d'assemblage

sub          esp,0E4h

Expliquez ici,sub C'est la soustraction. ,Ici.0E4h Représente un nombre hexadécimal ,hEst l'identificateur,Alors...0E4h En fait, c'est décimal. 228.

Ensemble, c'est esp Adresse stockée moins 0E4hTaille.

Parce qu'au - dessus, c'est une adresse basse, au - dessous, c'est une adresse haute,Donc moins0E4h C'est censé monter. .

espVers le Haut0E4h

MaintenantebpEtespCet espace est maintenu pourmainCadre de pile de fonctions ouvert par la fonction.

mainCadre de pile de fonctions

Jusqu'ici.,mainLe cadre de pile de fonctions de la fonction est ouvert et terminé.


mainInitialisation du cadre de pile de fonctions

Nous avons dû avoir un problème avec l'écriture du Code,Est d'imprimer avec des variables ou du contenu non initialisés,Résultats la sortie de la console est un résultat totalement inattendu.Par exemple:

Valeurs aléatoires
Pourquoi y a - t - il des valeurs aléatoires ici?

Voici la réponse.

Instructions d'assemblage

Les trois directives suivantes sont toutespush.

push                    ebx
push                    esi
push                    edi

Trois fois.pushFonctionnement

Trois fois.push Après la pile de pression ,esp Changement automatique de position pour ,mainLe cadre de pile de fonctions de la fonction augmente également.

Instructions d'assemblage

Et puis...:
lea: load effective address(Charger les adresses valides)

lea                                 edi,[ebp - 0E4h]

Plusieurs registres importants ont été décrits précédemment:

 Registre d'introduction
Donc iciediEst utilisé pour stocker l'adresse où l'initialisation a commencé,C'est - à - dire【ebp - 0E4h】 Cette adresse est placée dans ediGarde - le..

Instructions d'assemblage

Les deux opérations suivantes sont pour les registres d'initialisation:

mov                          ecx,39h
mov                          eax,0CCCCCCCCh

ecxEst le nombre de fois où le contenu initialisé est stocké,Donc C'est un39hCe nombre est enregistré dans le registreecxMoyenne.

EteaxEst de stocker le contenu à initialiser avec,Donc0CCCCCCCCh Stockage eaxDans le registre.

Les instructions suivantes sont la clé de l'initialisation:

rep stos                dword  ptr es:[edi]

dwordÇa veut dire...double word - UnwordC'est deux octets.,Donc undword- Oui.4Octets.

Toute la directive signifie ediLa position de stockage commence à être calculée tous les quatre octets vers le bas,Je répète.ecx Combien de fois la valeur stockée , Modifier tout cela comme suit: eax Valeur stockée dans .

C'est - à - dire deebp - 0E4h Position en bas. 39hLes positions des entiers sont initialisées à0CCCCCCCCh

Jusqu'ici.mainLe contenu du cadre de pile de fonctions a été entièrement initialisé.

Contenu de la mémoire

Ce qui se passe dans la pile :

 Situation dans la pile

Pour éviter que certains amis ne croient pas, Ici, nous calculons une vague .

Hexadécimal39h Convertir en décimal oui 57.

Calculatrice
57Une fois,Une fois.4Octets,C'est - à - dire57Multiplié par4égal à228Octets.

Et hexadécimal 0E4hConvertir en décimal plus est égal à228.

Calculatrice
Donc jusqu'à présent,mainTout le contenu du cadre de pile de fonctions est initialisé à0CCCCCCCCh.


Création de variables temporaires.

Instructions d'assemblage

La directive ici n'est pas assez claire,Parce que le compilateur affiche le nom de la variable par défaut,Ce n'est pas le moment pour nous d'étudier des situations spécifiques,Donc nous devrions vérifier le nom de la variable d'affichage.

Cliquez sur
Cocher

Supprimer la case à cocher ,Les effets sont les suivants:

 Effet après vérification

Ici, vous pouvez voir clairement la position spécifique.

move                         dword ptr [ebp-8],0Ah

Hexadécimal0Ah Convertir en décimal, c'est - à - dire 10,Cette directive signifie que0Ah Mettez ce nombre dans [ebp-8]Emplacement.

C'est - à - direebp-8 Cet emplacement est attribué à la variable a, Assigner la valeur à l'intérieur de 10.

Voilà.a Créer de l'espace et assigner des valeurs

Instructions d'assemblage

move                                  dword ptr [ebp-14h],14h

Ibid., Les chiffres hexadécimaux ici 14hConvertir en décimal oui20,Oui.20Mets - le dedans.[ebp-14h]Emplacement.

Voilà.b Créer de l'espace et assigner des valeurs

Instructions d'assemblage

move                         dword ptr [ebp-20],0

Ibid.,Oui.0À[ebp-20h]Emplacement, C'est - à - dire cLes variables créent de l'espace et attribuent des valeurs.

Variablesc Créer de l'espace et assigner des valeurs

Instructions d'assemblage
On dirait qu'il y a un appel de fonction,Mais ce n'est pas le cas, Avant d'appeler une fonction ,Créez d'abord une copie temporaire des arguments dans la fonction d'appel, Puis appelez la fonction , Ensuite, une analyse .

move               eax,dwor ptr [ebp-14h]

Cette directive signifie que [ebp-14h] Valeur stockée en position assignée à eaxRegistres.

Et nous pouvons voir:ebp - 14hCe n'est pas là que nous venons de créerbVariable??

Cette action prend les arguments b Valeur stockée dans le registre eaxMoyenne.

La prochaine directive :

push               eax

Oui.eaxPile de pression, On s'en souviendra. eaxLa valeur stockée dans est l'argumentbValeur de.

push
Instructions d'assemblage

move            ecx,dword ptr [ebp-8]
push             ecx

Ibid.,Oui.[ebp-8] La valeur de la position est placée dans ecx- Oui.,AprèsecxPile de pression.

Etebp-8 La position est aVariables.

Pile de pression

Faites - le ici.,En fait, il n'est pas difficile de voir que l'opération ci - dessus donneAddParamètres de transfert de fonction,Ouvrir deux espaces pour les copies temporaires des arguments.

Attention!: L'ordre dans lequel les paramètres sont transmis ici est le premierbPostbiographiea,Et c'estmainFait à l'intérieur du cadre de pile de la fonction.

AddCréation d'un cadre de pile de fonctions

CréationAddAvant le cadre de pile de fonctions de la fonction,Le compilateur a aussi fait une chose:

Instructions d'assemblage

call                             00B910E1

À première vue, cette directive semble très étrange,Mais nous allons procéder à la mise en service,Jusqu'àcall Pour commander, appuyez sur F11 Déboguer par instruction .

Va passer à cette étape .
jmpDéclarations
C'est ça.callLa prochaine directive de la directive,Le compilateur stocke la prochaine instruction après l'appel de la fonction sur la pile,Après le retour de la fonction appelée,Les instructions qui doivent être exécutées après l'appel de la fonction peuvent être exécutées directement à partir de cette adresse.

À ce stade, la rigueur de l'appel du compilateur au cadre de pile de fonctions peut être démontrée.

Considérez à la fois comment appeler une fonction pour allouer de l'espace,Considérez également comment la fin de l'appel de fonction retourne à l'instruction suivante qui aurait dû être exécutée.

StockagecallLa prochaine directive de la directive

Et ça a commencé. AddCréation d'un cadre de pile de fonctions.


🧑AddCréation d'un cadre de pile de fonctions

Instructions d'assemblage
Attention à la première action :

push                 ebp

Tiens.ebpValeur stockée dans la pile de pression,C'est - à - dire que cet endroit est stocké à l'origineebpEmplacement indiqué.

Pile de pression
Le marquage est donné ici : ebp:main

Ça veut dire ici. ebpCe qui est stockémain Position du bas de la pile de fonctions ,Dans le futurpop Ça en vaut la peine. ebp Rebond direct main Position du bas de la pile de fonctions , Et continuer à entretenir mainFonctions.

Instructions d'assemblage

Opérations et développements ultérieurs main Les cadres de pile de fonctions sont très similaires :

mov                   ebp,esp
sub                    esp,0CCh

D'abord.esp La position pointée est assignée à ebp,Voilà.ebpÇa va aller avecesp Pointez au même endroit ,Comme le bas de la pile qui va ouvrir le cadre de la pile.

Encore.espMoins0CChValeur de, C'est - à - dire le décalage vers le Haut 0CChLongueur des octets,Hexadécimal0CChConvertir en décimal en204. C'est - à - dire que le compilateur AddTaille du cadre de pile de fonctions attribué par la fonction.

Note:: L'allocation de l'espace de cadre de pile est laissée à la discrétion du compilateur, Estimation sans personne morale .

En ce momentebpÀespLa partie entre les deux est le compilateur pourAddCadre de pile de fonctions attribué par la fonction.

AddCadre de pile de fonctions


AddInitialisation du cadre de pile de fonctions

EtmainMême fonction,Après la création du cadre de pile de fonctions,Les cadres de pile de fonctions sont appariés à travers trois registres

Initialisation,Encore une fois, je vais vous montrer le Registre.:

 Fonction du Registre

Instructions d'assemblage
Trois d'abord. pushDirectives

push              ebx
push              esi
push              edi

Opération Stack
Instructions d'assemblage

J'ai déjà parlé de:

lea:load effective address(Charger les adresses valides)

lea                          edi,[ebp+FFFFFF34h]
move                      ecx,33h
move                      eax,0CCCCCCCCh

La directive signifie :

  1. Oui.[ebp+FFFFFF34] Charger l'adresse dans le registre ediMoyenne.
  2. Oui.33hMettez - le dans le registre comme un nombre de foisecxMoyenne.
  3. Oui.0CCCCCCCChStocké comme contenu à initialiser danseaxMoyenne.

EtFFFFFF34La séquence binaire de est:11111111111111111111111100110100

Apparemment.,C'est un nombre négatif.,Tous lesebp+FFFFFF34En fait, son adresse diminue,Donc l'emplacement de stockage à ce moment - là est en fait calculable.
 Obtenir la position de départ de l'initialisation

Nombre hexadécimal33h La forme décimale de 51, C'est - à - dire répéter 51 Dépassement de la valeur secondaire .

La valeur de couverture est 0CCCCCCCCh.
Instructions d'assemblage

rep stos           dword ptr es:[edi]

La dernière instruction est de ediLa position du registre commence à descendre33h Dépassement de la valeur secondaire , Overlay as 0CCCCCCCCh.

Add Après l'initialisation de la fonction

AddLa fonction implémente l'addition

Instructions d'assemblage

mov         dword ptr [edp-8],0

C'est l'étape pour créer une variable temporaire.

Oui.0Àedp-8Emplacement, C'est - à - dire donner des variables z A créé un espace .

CréationzVariables

Instructions d'assemblage

mov               eax,dword ptr [ebp+8]

Oui.ebp+8La valeur de la position est placée dans le registreeaxEnregistrer.

Comme vous pouvez le voir sur l'image ,ebp+8 à partir de mainDans la copie temporaire des arguments passés par la fonction10.

ebp+8Emplacement

En ce moment

eax: 10

add                  eax,dword ptr [ebp+0Ch]

Ici, nous pouvons calculer ,0Ch Convertir en décimal, c'est - à - dire 12,Tous lesebp+12 Ça devrait être à partir de maintenant. ebp Position vers le bas 3Une grille.( Parce qu'une grille est 4Octets).

Trouverebp+0ChEmplacement:

ebp+0Ch

Ajoutez les valeurs dans ce registreeaxÀ mi - chemin:

En ce moment

eax: 30

Instructions d'assemblage

mov                      dword ptr [ebp-8],eax

Registreeax La valeur de [ebp-8] En position .

zLa valeur de30

La fonction de calcul est maintenant terminée.

🧨AddLa valeur de retour de la fonction est implémentée

Après la mise en œuvre de la fonction , Vous êtes sur le point de retourner la valeur de la fonction .

Instructions d'assemblage

mov                         eax,dword ptr [ebp-8]

Directives:Oui.[ebp-8] La valeur de l'adresse est placée dans eaxRegistres,C'est - à - dire qu'en prenant les résultats que nous venons de calculer30 Enregistrer dans le registre .

AddDestruction du cadre de pile de fonctions

pop Est une instruction de sortie de pile ,éjecter la valeur de la pile à l'endroit spécifié.

pop               edi
pop               esi
pop               ebx

Trois d'affilée.pop, Initialiser avant AddLa fonction est l'éjection des trois éléments de la pile de pression.

popHors de la pile
Après que les trois éléments sortent de la pile ,AddLe cadre de pile de la fonction diminue,espLa position pointée change aussi au hasard.

Instructions d'assemblage

mov                               esp,ebp

Comme lors de la création d'un cadre de pile de fonctions,Mais c'est différent,Oui.ebpValeur attribuée àesp.
C'est - à - dire:esp Pointera directement vers ebpPosition pointée.

espPointageebpPosition indiquée
Une fois les instructions d'opération ci - dessus exécutées,Ce qui signifieesp,ebpLes deux registres ne sont plus tenus à jourAdd Cadre de pile de fonctions ,Tout l'espace ouvert sera retourné au système d'exploitation.

 L'état du cadre de pile pour le moment

Instructions d'assemblage

pop                           ebp

éjecter l'élément supérieur de la pile versebpEmplacement.

Remarquez les éléments placés au Sommet de la pile ici: Éléments placés en haut de la pile

Comme indiqué précédemment , Pile de pression ici ebpObjet, C'est pour détruire. AddAprès la fonctionebpOn peut trouvermain Position inférieure de la pile de fonctions , Et continuer à entretenir main Cadre de pile pour la fonction .

 Aperçu de ce qui précède

Donc cette directive va faire ebpPoint originalmain Bas de la pile de fonctions .

 Le cadre de la pile de fonctions

En ce momentAddLes cadres de pile de fonctions ont tous été détruits.


Retour àmainInstruction de fonction

Et puis...espC'est ça.00B910E1.

Comme mentionné précédemment,C'estcallLa prochaine instruction qui appelle l'instruction, Alors retournez directement à main Instruction suivante de la fonction .

 Commande pop - up
Déboguer maintenant la presse de désassemblage F10 Directement à partir de AddLa fonction passe àmainFonctionscallLa prochaine directive de la directive.

callLa prochaine directive de la directive

add                          esp,8

Prends ça.8Plus.espRegistres,Déplacez les deux cellules vers le bas( Une grille 4Octets)

esp Deux unités vers le bas
Les deux éléments supérieurs de la pile ne sont plus maintenus,mainLes cadres de pile de fonctions de la fonction sont également réduits.

Instructions d'assemblage

mov                           dword ptr [ebp-20h],eax

Oui.eax Valeur dans le registre assignée à ebp-20hEmplacement,eaxC'est nous.AddValeur de retour stockée après le calcul dans la fonction(30),ebp-20 Variable de temps de position pour cAdresse.

c Modification des valeurs

Jusqu'ici.,AddFonctions de la fonction,Les cadres de pile sont expliqués à la fin.

Résumé

Connaissance des cadres de pile de fonctions utilisant le langage d'assemblage,Voir la relation d'un appel de fonction sous l'angle le plus bas.

Les problèmes au début de l'article devraient être résolus en lisant ceci.

Votre attention, s'il vous plaît.:Comprendre le cadre de la pile de fonctions ne vous permet pas d'écrire plus de code, L'algorithme de brossage est plus puissant ,Le cadre de la pile de fonctions n'est qu'une existence similaire à la culture des compétences internes,La logique sous - jacente nous aide à réfléchir à des questions plus complexes,

Par exemple, algorithme récursif ,L'idée d'un cadre de pile de fonctions est facile à saisir.

Enfin,N'oublie pas d'aimer+Collection+ Attention à la marche ~

版权声明
本文为[Aaronskr]所创,转载请带上原文链接,感谢
https://chowdera.com/2021/10/20211013211740531o.html

随机推荐