J'essaie de comprendre comment les cadres de pile sont construits et quelles variables (paramètres) sont poussées pour s'empiler dans quel ordre? Certains résultats de recherche ont montré que le compilateur C / C ++ décide en fonction des opérations effectuées dans une fonction. Par exemple, si la fonction était censée simplement incrémenter une valeur int transmise de 1 (similaire à l'opérateur ++) et la renvoyer, elle placerait tous les paramètres de la fonction et les variables locales dans des registres.
Je me demande quels registres sont utilisés pour les paramètres renvoyés ou passés par valeur. Comment les références sont-elles retournées? Comment le compilateur choisit-il entre eax, ebx, ecx et edx?
Que dois-je savoir pour comprendre comment les registres, les références de pile et de tas sont utilisés, créés et détruits lors des appels de fonction?
Réponses:
En plus de ce que Dirk a dit, une utilisation importante des trames de pile est de sauvegarder les valeurs précédentes des registres afin qu'ils puissent être restaurés après un appel de fonction. Ainsi, même sur les processeurs où des registres sont utilisés pour transmettre des paramètres, renvoyer une valeur et enregistrer l'adresse de retour, les valeurs de ces registres sont enregistrées sur la pile avant un appel de fonction afin de pouvoir être restaurées après l'appel. Cela permet à une fonction d'en appeler une autre sans écraser ses propres paramètres ni oublier sa propre adresse de retour.
Ainsi, appeler une fonction B à partir de la fonction A sur un système "générique" typique peut impliquer les étapes suivantes:
Ce n'est en aucun cas la seule façon dont les appels de fonction peuvent fonctionner (et j'ai peut-être une étape ou deux en panne), mais cela devrait vous donner une idée de la façon dont la pile est utilisée pour permettre au processeur de gérer les appels de fonction imbriqués.
la source
push
etpop
sont les deux opérations fondamentales sur une pile. Une pile est une structure de dernier entré, premier sorti, comme une pile de livres. Lorsque vouspush
, vous placez un nouvel objet au-dessus de la pile; lorsque vouspop
prenez un objet du haut de la pile. Vous n'êtes pas autorisé à insérer ou supprimer des objets au milieu, vous ne pouvez opérer que sur le dessus de la pile. Vous pouvez en savoir plus sur les piles en général et la pile de programmes en particulier sur Wikipedia.Cela dépend de la convention d'appel utilisée. Celui qui définit la convention d'appel peut prendre cette décision comme bon lui semble.
Dans la convention d'appel la plus courante sur x86, les registres ne sont pas utilisés pour transmettre des paramètres; les paramètres sont poussés sur la pile en commençant par le paramètre le plus à droite. La valeur de retour est placée dans eax et peut utiliser edx si elle a besoin de l'espace supplémentaire. Les références et les pointeurs sont tous deux retournés sous la forme d'une adresse en eax.
la source
Si vous comprenez très bien la pile, vous comprendrez comment la mémoire fonctionne dans le programme et si vous comprenez comment la mémoire fonctionne dans le programme, vous comprendrez comment le magasin de fonctions dans le programme et si vous comprenez comment le magasin de fonctions dans le programme, vous comprendrez comment fonctionne la fonction récursive et si vous comprenez comment fonctionne la fonction récursive vous comprendrez comment fonctionne le compilateur et si vous comprenez comment fonctionne le compilateur votre esprit fonctionnera comme compilateur et vous déboguerez n'importe quel programme très facilement
Permettez-moi d'expliquer comment fonctionne la pile:
Vous devez d'abord savoir comment stocker les fonctions dans la pile:
Stockage dynamique des valeurs d'allocation de mémoire dynamique. Stockez les valeurs d'allocation et de suppression automatiques.
Comprenons par exemple:
Comprenez maintenant certaines parties de ce programme:
Voyons maintenant ce qu'est la pile et quelles sont les pièces de la pile:
Souvenez-vous d'une chose si une fonction obtient un «retour», qu'elle ait chargé toutes ses variables locales ou quoi qu'elle revienne immédiatement de la pile dans son cadre de pile. Cela signifie que lorsqu'une fonction récursive obtient la condition de base et que nous mettons return après la condition de base afin que la condition de base n'attende pas pour charger les variables locales qui sont situées dans la partie "else" du programme, elle retournera immédiatement l'image actuelle de la pile et maintenant si une image retourner l'image suivante est dans le dossier d'activation. Voir ceci en pratique:
Alors maintenant, chaque fois qu'une fonction trouve l'instruction return, elle supprime l'image courante de la pile.
en revenant de la valeur de pile retournera dans l'ordre inverse de l'ordre dans lequel ils ont alloué dans la pile.
Ce sont des descriptions très courtes et si vous voulez en savoir plus sur la pile et la double récursivité, lisez deux articles de ce blog:
En savoir plus sur la pile étape par étape
En savoir plus sur la double récursivité pas à pas avec la pile
la source
Ce que vous recherchez s'appelle Application Binary Interface - ABI.
Il existe une spécification pour chaque compilateur qui définit l'ABI.
Chaque plate-forme spécifie généralement et ABI afin de prendre en charge l'interopérabilité entre les compilateurs. Par exemple, les conventions d'appel x86 expliquent les conventions d'appel typiques pour x86 et x86-64. J'attendrais cependant un document plus officiel que wikipedia.
la source