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?
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.
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.
Si vous comprenez très bien la pile, vous comprendrez comment fonctionne la mémoire 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:
def hello(x):
if x==1:
return "op"
else:
u=1
e=12
s=hello(x-1)
e+=1
print(s)
print(x)
u+=1
return e
hello(4)
Comprenez maintenant certaines parties de ce programme:
Voyons maintenant ce qu'est la pile et quelles sont les pièces de la pile:
Attribution 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 pour 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:
Désallocation du bloc:
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:
Plus d'informations sur la pile étape par étape
En savoir plus sur la récursivité double étape par étape avec la pile
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, Conventions d'appel x86 définit les conventions d'appel typiques pour x86 et x86-64. Je m'attendrais à un document plus officiel que wikipedia cependant.