2010-08-15 4 views
2

très rapide question pour vous. Lorsque je stocke une variable automatique en C, la sortie asm est comme ceci: MOV ESP+4,#25h, et je veux juste savoir pourquoi compilateur can't calculer que ESP+4 adresse lui-même.Une autre question sur la sortie ASM compilateur C

J'ai pensé cela, et je ne peux vraiment pas trouver de raison pour cela. Je veux dire, le compilateur n'est pas conscient de la valeur esp? CA devrait etre. Et lors de l'utilisation d'un autre fichier objet, cela ne devrait pas non plus poser de problème, puisque les variables pourraient simplement être représentées par adresse et reliées plus tard, lorsque toutes les variables automatiques sont connues, et que l'adresse correcte pourrait être assignée. Merci.

Répondre

3

Non, il ne peut pas connaître la valeur de esp à l'avance. Prenons par exemple une fonction récursive, c'est-à-dire

une fonction qui s'appelle elle-même. Supposons qu'une telle fonction a plusieurs paramètres qui sont transmis via la pile. Cela signifie que chaque argument prend de l'espace sur la pile, modifiant ainsi la valeur du registre esp.

Maintenant, lorsque la fonction est entrée, la valeur exacte de esp dépendra du nombre de fois que la fonction s'est appelée elle-même précédemment, et il est impossible que le compilateur puisse le savoir au moment de la compilation. Si vous en doutez, prenez une fonction telle que celle-ci:

void foobar(int n) 
{ 
    if (rand() % n != 17) 
     foobar(n + 1); 
} 

Il n'y a aucun moyen le compilateur serait assez intelligent à l'avance pour savoir si la fonction elle-même appeler une fois de plus.

Si le compilateur voulait déterminer à l'avance esp, il devrait effectivement créer une version de la fonction pour chaque valeur possible pour esp.

L'explication ci-dessus ne prend en compte qu'une seule fonction. Dans un scénario réel, un programme a de nombreuses fonctions qui s'interpénètrent les unes sur les autres, ce qui se traduit par des «graphiques d'appel» assez complexes. Ceci avec (entre autres choses) une logique de programme imprévisible signifie que le compilateur devrait créer un grand nombre de versions de chaque fonction, juste pour optimiser sur esp - ce qui n'a évidemment aucun sens.


P.S .: maintenant quelque chose d'autre. Vous n'avez pas vraiment besoin d'optimiser [esp+N] du tout, car il ne devrait pas prendre plus de temps CPU que le plus simple [esp] ... du moins pas sur les processeurs Intel Pentium. On pourrait dire qu'ils contiennent déjà des optimisations pour exactement cela et des scénarios encore plus compliqués. Si vous êtes intéressé par les processeurs Intel, je vous suggère de rechercher dans la documentation quelque chose appelé MOD R/M et SIB octet d'une instruction machine, par ex.here for the SIB byte ou here ou, bien sûr, dans la documentation officielle des développeurs d'Intel.

+0

Juste une question de plus, si vous n'utilisiez aucun appel de fonction récursive dans le programme entier, cela pourrait-il être fait sans utiliser l'adressage indirect? –

+0

_ @ b-gen-jack-o-neill: _ Ça rendrait les choses plus faciles. Disons qu'il est clair qu'une fonction 'caller' appelle votre fonction cible' f'. Ensuite, 'esp' pourrait être calculé sur la base de la valeur' esp' supposée pour 'caller', plus éventuellement l'espace requis par les variables locales de' caller' et les arguments de 'f'. (Il peut en fait ne pas être si simple.) La fonction récursive ci-dessus pourrait être transformée en fonctions * n * + 1 presque identiques (une par itération, où * n * est le nombre de fois que la fonction s'appelle elle-même; la valeur supposée pour 'esp'). – stakx

+0

_ @ b-gen-jack-o-neill: _ Veuillez également lire le P.S. ajouté. à ma réponse. Il répond à la question assez importante de savoir si vous devez "optimiser" '[esp + N]' du tout. – stakx

3

Non, le compilateur n'a pas connaissance de la valeur ESP lors de l'exécution - c'est le pointeur de la pile. Il est potentiellement différent chaque fois que la fonction est appelée. L'exemple le plus simple à envisager est peut-être une fonction récursive - chaque fois qu'elle s'appelle elle-même, la pile devient un peu plus profonde pour accommoder les variables locales pour le nouvel appel. Chaque frame de pile a sa propre variable locale, chaque frame de pile est à une position différente sur la pile, et a donc sa propre adresse (en ESP, normalement).

1

Ceci est vraiment fondamental dans le fonctionnement de la pile. Pour le raisonner par vous-même, imaginez comment vous implémenteriez une fonction récursive.

2

Le pointeur de pile ne peut pas être calculé au moment de la compilation. Pour un exemple simple, pourquoi cela n'est pas possible, pensez à une fonction récursive: La même variable a une adresse différente pour chaque appel, mais c'est toujours le même code qui est exécuté.

2

Non, le compilateur ne connaît pas la valeur à l'avance. Dans quelques programmes très basiques (où il n'y a qu'un seul "itinéraire" possible de main à toute autre fonction particulière appelée) pourrait, mais je ne connais pas un compilateur qui tente de le calculer. Si vous avez une récursivité ou si une fonction est appelée depuis plusieurs endroits, le pointeur de la pile aura des valeurs différentes selon l'endroit d'où elle a été appelée. Le pointeur de pile est si fortement utilisé, la plupart des processeurs sont conçus pour rendre l'adressage indirect du pointeur de la pile extrêmement efficace. En fait, c'est souvent plus efficace que de fournir une adresse absolue.