2008-09-24 6 views
29

Existe-t-il un moyen de connaître et de générer la taille de pile requise par une fonction lors de la compilation en C? Voici ce que je voudrais savoir:Vérification de l'utilisation de la pile au moment de la compilation

Prenons une fonction:

void foo(int a) { 
    char c[5]; 
    char * s; 
    //do something 
    return; 
} 

Lors de la compilation de cette fonction, je voudrais savoir combien d'espace pile, il consommera Whent il est appelé. Cela peut être utile pour détecter la déclaration sur la pile d'une structure cachant un gros tampon.

Je cherche quelque chose qui imprimerait quelque chose comme ceci:

fichier foo.c: fonction utilisation foo stack est n octets

Est-il possible de ne pas regarder l'ensemble généré à savoir que ? Ou une limite qui peut être définie pour le compilateur? Mise à jour: Je ne cherche pas à éviter le débordement de la pile d'exécution pour un processus donné, je cherche un moyen de trouver avant l'exécution, si une utilisation de la pile de fonctions, telle que déterminée par le compilateur, est disponible en sortie du processus de compilation.

En d'autres termes: est-il possible de connaître la taille de tous les objets locaux d'une fonction? Je suppose que l'optimisation du compilateur ne sera pas mon ami, car une variable va disparaître mais une limite supérieure est bonne.

+0

Au cas où vous vous poseriez, j'ai tapé le caractère secret '}' –

+0

La question ne me semble pas claire. Je suppose que si vous écrivez plus sur pourquoi vous voulez savoir ceci et pourquoi vérifier le désassemblage ou l'exécutable (qui est la manière la plus facile de vérifier la sortie du compilateur) n'est pas acceptable, peut-être quelqu'un pourrait trouver une solution facile? – Suma

Répondre

10

Le code noyau Linux s'exécute sur une pile 4K sur x86. Par conséquent, ils se soucient. Qu'est-ce qu'ils utilisent pour vérifier cela, est un script Perl qu'ils ont écrit, que vous pouvez trouver en tant que scripts/checkstack.pl dans une archive récente du noyau (2.6.25 l'a eu). Il s'exécute sur la sortie de objdump, la documentation d'utilisation est dans le commentaire initial.

Je pense que je l'ai déjà utilisé pour les binaires de l'espace utilisateur il y a des lustres, et si vous connaissez un peu la programmation perl, il est facile de résoudre ce problème s'il est cassé.

Quoi qu'il en soit, il s'agit essentiellement de regarder automatiquement la sortie de GCC. Et le fait que les pirates du noyau aient écrit un tel outil signifie qu'il n'y a pas de manière statique de le faire avec GCC (ou peut-être qu'il a été ajouté très récemment, mais j'en doute). Btw, avec objdump du projet mingw et ActivePerl, ou avec Cygwin, vous devriez pouvoir le faire aussi sur Windows et aussi sur les binaires obtenus avec d'autres compilateurs.

+5

Mise à jour: Michael Greene a noté ci-dessous que GCC 4.6 a -fstack-usage disponible pour C: gcc.gnu.org/gcc-4.6/changes.html; -fstack-usage est décrit ci-dessous dans la réponse de shodanex ci-dessous: http://stackoverflow.com/a/126490/53974. – Blaisorblade

1

Seul le compilateur saurait vraiment, puisque c'est le gars qui met tous vos trucs ensemble. Vous devriez regarder l'assemblage généré et voir combien d'espace est réservé dans le préambule, mais cela ne tient pas vraiment compte des choses comme alloca qui font leur chose à l'exécution.

+0

Théoriquement théoriques analyseurs de code outils tels charpie peuvent faire le travail, pratiquement je ne pense pas qu'ils le font. – Ilya

-1

Pas en général. Le problème de l'arrêt en informatique théorique suggère que vous ne pouvez même pas prédire si un programme général s'arrête sur une entrée donnée. Le calcul de la pile utilisée pour un programme en général serait encore plus compliqué. Donc non. Peut-être dans des cas spéciaux. Imaginons que vous ayez une fonction récursive dont le niveau de récursivité dépend de l'entrée qui peut être de longueur arbitraire et que vous n'avez pas de chance.

+0

Vous parlez de la pile de processus et non de l'utilisation de chaque appel à la fonction – shodanex

+0

Le problème d'arrêt n'arrête pas l'analyse statique (c'est-à-dire dans les compilateurs) et donne des réponses approximatives en consultant le texte du programme. En fait, un grand défi est le calcul lorsque deux programmes différents sont équivalents, donc deux programmes équivalents peuvent donner des résultats différents sous analyse statique. – Blaisorblade

3

Je ne vois pas pourquoi une analyse de code statique ne pourrait pas donner un chiffre suffisant pour cela. Il est trivial de trouver toutes les variables locales dans une fonction donnée, et la taille de chaque variable peut être trouvée par le standard C (pour les types intégrés) ou en le calculant (pour les types complexes comme les structures et les unions) . Bien sûr, la réponse ne peut pas être garantie à 100%, puisque le compilateur peut effectuer différentes sortes d'optimisations comme le remplissage, la mise de variables dans des registres ou la suppression complète de variables inutiles. Mais toute réponse donnée devrait être une bonne estimation au moins.

J'ai fait une recherche google rapide et trouvé StackAnalyzer mais je suppose que d'autres outils d'analyse de code statique ont des capacités similaires.

Si vous voulez un chiffre précis à 100%, alors vous devez regarder la sortie du compilateur ou vérifier lors de l'exécution (comme Ralph suggéré dans his reply)

+1

StackAnalyzer semble bien, mais il ne fait pas le travail demandé, car il analyse l'exécutable, pas le code source. Alors que l'écriture d'un tel outil devrait vraiment être possible en théorie, je ne pense pas qu'il existe un tel outil - la vérification de l'utilisation de la pile d'exécution ou basée sur l'assemblage est très pratique. – Suma

+0

Je dis juste un nom de fonction, et vous savez pourquoi l'analyse de code statique ne suffit pas pour obtenir l'espace de pile utilisé d'une fonction: alloca. Dès qu'une fonction l'utilise (avec une valeur non const), vous ne pouvez pas le faire. Autre chose déjà mentionnée: la récursivité. – flolo

8

StackAnlyser semble examinate le code exécutable lui-même plus quelques informations de débogage. Ce qui est décrit par this reply, c'est ce que je cherche, l'analyseur de pile me semble trop compliqué.

Quelque chose de semblable à ce qui existe pour l'ADA conviendrait. Regardez cette page de manuel du manuel moucheron:

22,2 Stack statique Analyse de l'utilisation

Unité compilé avec -fstack-utilisation va générer un fichier supplémentaire qui indique le montant maximum de la pile utilisée, sur une base par fonction base. Le fichier a le même nom de base que le fichier objet cible avec une extension .su. Chaque ligne de ce fichier est constitué de trois champs:

* The name of the function. 
* A number of bytes. 
* One or more qualifiers: static, dynamic, bounded. 

Le second champ correspond à la taille de la partie connue du cadre de fonction.

Le qualificateur statique signifie que la taille de la trame de la fonction est purement statique. Cela signifie généralement que toutes les variables locales ont une taille statique. Dans ce cas, le deuxième champ est une mesure fiable de l'utilisation de la pile de fonctions.

La qualificatif dynamique signifie que la taille de la trame de fonction n'est pas statique. Cela arrive surtout quand certaines variables locales ont une taille dynamique. Lorsque ce qualificatif apparaît seul, le second champ n'est pas une mesure fiable de l'analyse de la pile de fonctions. Quand il est qualifié avec bounded, cela signifie que le second champ est un maximum fiable de l'utilisation de la pile de fonctions.

+6

Ceci est une vieille question, mais fwiw GCC 4.6 a -fstack-usage disponible pour C: http://gcc.gnu.org/gcc-4.6/changes.html –

+1

@ Michael Greene: ce pourrait être une réponse! Je vous remercie ! – shodanex

1

En supposant que vous êtes sur une plate-forme intégrée, vous trouverez peut-être que votre chaîne d'outils a un objectif. De bons compilateurs intégrés commerciaux (comme, par exemple, le compilateur Arm/Keil) produisent souvent des rapports d'utilisation de la pile.

Bien sûr, les interruptions et les récursions sont généralement un peu au-dessus d'elles, mais cela vous donne une idée approximative si quelqu'un a commis une erreur terrible avec un tampon de plusieurs mégaoctets sur la pile quelque part.

1

Pas exactement « compilation », mais je ferais cela comme une étape de post-construction:

  • laisser l'éditeur de liens créer un fichier de carte pour vous
  • pour chaque fonction dans le fichier de carte lire la partie correspondante de l'exécutable, et analyser la fonction prologue.

Ceci est similaire à ce que fait StackAnalyzer, mais beaucoup plus simple. Je pense que l'analyse de l'exécutable ou du désassemblage est le moyen le plus simple d'obtenir la sortie du compilateur. Bien que le compilateur connaisse ces choses en interne, je crains que vous ne puissiez pas l'obtenir (vous pouvez demander au fournisseur du compilateur d'implémenter la fonctionnalité, ou si vous utilisez un compilateur open source, vous pouvez le faire vous-même ou laisser quelqu'un le faire pour toi).

Pour mettre en œuvre ce que vous devez:

  • pouvoir analyser carte fichier
  • comprendre le format de l'exécutable
  • savent ce qu'est un prologue de la fonction peut ressembler et être en mesure de « décoder » il

La facilité ou la difficulté dépend de votre plate-forme cible. (Embedded? Quelle architecture CPU? Quel compilateur?Tout cela peut certainement être fait en x86/Win32, mais si vous n'avez jamais rien fait de tel et que vous devez tout créer à partir de rien, cela peut prendre quelques jours avant que vous ayez fini .

Questions connexes