Essayer de comprendre l'option gcc-fomit-frame-pointer

j'ai demandé à Google de me donner le sens de la gcc option -fomit-frame-pointer , qui me redirige vers la déclaration ci-dessous.

- fomit-frame-pointer

ne gardez pas le pointeur de cadre dans un registre pour les fonctions qui n'en ont pas besoin. Cela évite les instructions pour sauvegarder, configurer et restaurer les pointeurs de CADRE; cela rend également un registre supplémentaire disponible dans de nombreuses fonctions. Il fait aussi le débogage impossible sur certaines machines.

selon ma connaissance de chaque fonction, un enregistrement d'activation sera créé dans la pile de la mémoire de processus pour conserver toutes les variables locales et quelques informations supplémentaires. J'espère que ce pointeur signifie l'adresse de l'enregistrement d'activation d'une fonction.

dans ce cas, quel est le type de fonctions pour lesquelles il n'est pas nécessaire de conserver le pointeur de cadre dans un registre? Si j'obtiens cette information, j'essaierai pour concevoir la nouvelle fonction basée sur cela (si possible) parce que si le pointeur de cadre n'est pas conservé dans les registres, certaines instructions seront omises en binaire. Cela va vraiment améliorer la performance de façon notable dans une application où il ya beaucoup de fonctions.

64
demandé sur trentcl 2013-02-03 01:21:46

2 réponses

la plupart des petites fonctions n'ont pas besoin d'un pointeur de cadre - les plus grandes fonctions peuvent en avoir besoin.

il s'agit en fait de savoir comment le compilateur parvient à suivre comment la pile est utilisée, et où les choses se trouvent sur la pile (variables locales, arguments passés à la fonction courante et arguments préparés pour une fonction sur le point d'être appelée). Je ne pense pas qu'il soit facile de caractériser les fonctions qui ont besoin ou n'ont pas besoin d'un pointeur de cadre (techniquement, aucune fonction ne doit avoir pointeur de l'image - c'est plus une affaire de "si le compilateur considère nécessaire de réduire la complexité du code").

Je ne pense pas que vous devriez" essayer de faire des fonctions n'ont pas de pointeur de cadre "dans le cadre de votre stratégie de codage - comme je l'ai dit, les fonctions simples n'ont pas besoin d'eux, donc utilisez -fomit-frame-pointer , et vous obtiendrez un registre de plus disponible pour le registre allocator, et sauver 1-3 instructions sur l'entrée/sortie aux fonctions. Si votre fonction a besoin d'un pointeur de cadre, c'est parce que le compilateur décide que c'est mieux que de ne pas utiliser un pointeur de l'image. Ce n'est pas un but d'avoir des fonctions sans pointeur de cadre, c'est un but d'avoir du code qui fonctionne à la fois correctement et rapidement.

notez que "ne pas avoir de pointeur de cadre" devrait donner de meilleures performances, mais ce n'est pas une balle magique qui donne des améliorations énormes - en particulier pas sur x86-64, qui a déjà 16 registres pour commencer. Sur x86 32 bits, puisqu'il n'y a que 8 registres, qui est le pointeur de pile, et de prendre un autre que le pointeur de cadre signifie 25% de l'espace de Registre est prise. Changer cela à 12,5% est une nette amélioration. Bien sûr, la compilation 64 bits aidera beaucoup trop.

45
répondu Mats Petersson 2018-05-21 14:46:30

il s'agit du registre BP/EBP/RBP sur les plateformes Intel. Ce registre renvoie par défaut au segment stack (il n'a pas besoin d'un préfixe spécial pour accéder au segment stack).

L'EBP est le meilleur choix de Registre pour accéder aux structures de données, aux variables et à l'espace de travail attribué dynamiquement à l'intérieur de la pile. EBP est souvent utilisé pour accéder aux éléments sur la pile par rapport à un point fixe sur la pile plutôt que par rapport à la TOS courante. Généralement, il identifie l'adresse de base du cadre de la pile actuelle établie pour la procédure courante. Lorsque EBP est utilisé comme registre de base dans un calcul de décalage, le décalage est calculé automatiquement dans le segment de pile courant (c.-à-d. le segment actuellement sélectionné par SS). Comme SS ne doit pas être spécifié explicitement, le codage d'instruction est plus efficace dans de tels cas. Les EBP peuvent également être utilisés pour indexer en segments adressables via d'autres registres de segments.

(source - http://css.csail.mit.edu/6.858/2017/readings/i386/s02_03.htm )

puisque sur la plupart des plateformes 32 bits, segment de données et segment de pile sont les mêmes, cette association EBP/RBP avec la pile n'est plus un problème. Il en va de même pour les plates-formes 64 bits: l'architecture x86-64, introduite par AMD en 2003, a largement perdu le support de la segmentation en mode 64 bits: quatre des registres de segments: CS, SS, DS, et ES sont forcés à 0. Ces circonstances des plates-formes x86 32 bits et 64 bits signifient essentiellement que le registre EBP/RBP peut être utilisé, sans préfixe, dans les instructions du processeur qui accèdent à la mémoire.

ainsi l'option de compilateur sur laquelle vous avez écrit permet D'utiliser la BP/EBP/RBP pour d'autres moyens, par exemple pour maintenir une variable locale.

par "cela évite les instructions pour sauvegarder, configurer et restaurer les pointeurs de cadre" est censé éviter le code suivant sur l'entrée de chaque de la fonction:

push ebp
mov ebp, esp

ou l'instruction enter , très utile sur les processeurs Intel 80286 et 80386.

également, avant le retour de la fonction, le code suivant est utilisé:

mov esp, ebp
pop ebp 

ou l'instruction leave .

les outils de débogage peuvent numériser les données de la pile et utiliser ces données de registre EBP poussées tout en localisant call sites , c.-à-d. pour afficher les noms de la fonction et de la arguments dans l'ordre ils ont été appelés hiérarchiquement.

programmeurs peuvent avoir des questions sur les cadres de pile pas dans un terme large (que c'est une entité unique dans la pile qui sert juste un appel de fonction et conserve adresse de retour, arguments et variables locales) mais dans un sens étroit – quand le terme stack frames est mentionné dans le contexte des options de compilateur. Du point de vue du compilateur, un cadre de pile n'est que le code d'entrée et de sortie routine , qui pousse une ancre à la pile – qui peut également être utilisé pour le débogage et pour la gestion des exceptions. Les outils de débogage peuvent balayer les données de la pile et utiliser ces ancres pour retracer, tout en localisant call sites dans la pile, c'est-à-dire pour afficher les noms de la fonction dans l'ordre où ils ont été appelés hiérarchiquement.

c'est pourquoi il est très important de comprendre pour un programmeur ce qu'est un cadre de pile en termes d'options de compilateur – parce que le compilateur peuvent générer ce code ou pas.

dans certains cas, le cadre de la pile (code d'entrée et de sortie pour la routine) peut être omis par le compilateur, et les variables seront directement accessibles via le pointeur de la pile (SP/ESP/RSP) plutôt que le pointeur de base pratique (BP/ESP/RSP). Les Conditions pour qu'un compilateur omette les cadres de la pile pour certaines fonctions peuvent être différentes, par exemple: (1) la fonction est une fonction de feuille (c.-à-d. une entité finale qui n'appelle pas autres fonctions); (2) AUCUNE EXCEPTION n'est utilisée; (3) aucune routine n'est appelée avec des paramètres sortants sur la pile; (4) la fonction n'a pas de paramètres.

omettre les cadres de la pile (code d'entrée et de sortie pour la routine) peut rendre le code plus petit et plus rapide, mais peut aussi affecter négativement la capacité des débogueurs de retracer les données dans la pile et de les afficher au programmeur. Ce sont les options du compilateur qui déterminent dans quelles conditions une fonction doit satisfaire en ordonnez au compilateur de l'attribuer avec le code d'entrée et de sortie du cadre de pile. Par exemple, un compilateur peut avoir des options pour ajouter ce code d'entrée et de sortie aux fonctions dans les cas suivants: (a) toujours, (B) jamais, (c) Quand nécessaire (en spécifiant les conditions).

retour des généralités aux particularités: si vous utilisez l'option -fomit-frame-pointer compilateur GCC, vous pouvez gagner à la fois sur le code d'entrée et de sortie pour la routine, et sur avoir un registre supplémentaire (à moins qu'il ne soit déjà activé par défaut soit lui-même soit implicitement par d'autres options, dans ce cas, vous bénéficiez déjà du gain d'utiliser le registre EBP/RBP et aucun gain supplémentaire ne sera obtenu en spécifiant explicitement cette option si elle est déjà activée implicitement). Veuillez noter, cependant, que dans les modes 16-bit et 32-bit, le registre BP n'a pas la capacité d'accéder à des parties 8-bit comme AX a (AL et AH).

depuis cette option, en plus de permettre au compilateur de utiliser EBP comme un registre universel dans les optimisations, empêche également la génération de code de sortie et d'entrée pour le cadre de la pile qui complique le débogage -- c'est pourquoi la documentation GCC déclare explicitement (en soulignant de manière inhabituelle avec un style Gras) que l'activation de cette option rend le débogage impossible sur certaines machines

s'il vous plaît également être conscient que d'autres options de compilateur, liées au débogage ou à l'optimisation, peuvent activer ou désactiver implicitement l'option -fomit-frame-pointer .

Je n'ai pas trouvé d'informations officielles à gcc.gnu.org à propos de la façon dont les autres options affectent -fomit-frame-pointer sur les plates-formes x86 , le https://gcc.gnu.org/onlinedocs/gcc-3.4.4/gcc/Optimize-Options.html indique seulement ce qui suit:

- O tourne également sur-fomit-frame-pointer sur les machines où cela n'interfère pas avec débogage.

il n'est donc pas clair de la documentation en soi si -fomit-frame-pointer sera activé Si vous compilez avec une seule option -O sur la plate-forme x86. Il peut être testé empiriquement, mais dans ce cas il n'y a aucun engagement de la part des développeurs de GCC à ne pas changer le comportement de cette option à l'avenir sans préavis.

Toutefois, Peter Cordes , a souligné dans les commentaires qu'il ya une différence pour les paramètres par défaut de la -fomit-frame-pointer entre les plates-formes x86-16 et x86-32/64 plates-formes.

cette option -- -fomit-frame-pointer -- est aussi pour le compilateur Intel c++ 15.0 , pas seulement pour le GCC:

pour le compilateur Intel, cette option a un alias /Oy .

voici ce Qu'Intel a écrit à ce sujet:

ces options déterminent si EBP est utilisé comme un registre général dans les optimisations. Options-fomit-frame-pointer et /Oy permettent cette utilisation. Options-fno-omit-frame - pointer et /Oy-disallow it.

certains débogueurs s'attendent à ce que EBP soit utilisé comme pointeur de cadre de pile, et ne peuvent pas produire un backtrace de pile à moins que ce ne soit le cas. Les options-fno-omit-frame-pointer et /Oy - guident le compilateur pour générer du code qui maintient et utilise EBP comme pointeur de frame stack pour toutes les fonctions de sorte qu'un débogueur puisse toujours produire un backtrace de pile sans faire ce qui suit:

pour-fno-omit-frame-pointer: désactiver les optimisations avec -O0 Pour /Oy-: arrêt /O1, /O2, ou /O3 optimisations L'option-fno-omit-frame-pointer est définie lorsque vous spécifiez l'option-O0 ou l'option-G. L'option-fomit-frame-pointer est définie lorsque vous spécifiez l'option-O1, -O2 ou-O3.

l'option /Oy est définie lorsque vous spécifiez l'option /O1, /O2, ou /O3. L'Option / Oy-est définie lorsque vous spécifiez l'option /Od.

L'utilisation de l'option-fno-omit-frame-pointer ou /Oy réduit le nombre de registres polyvalents disponibles de 1 et peut entraîner un code légèrement moins efficace.

NOTE pour les systèmes Linux*: il y a actuellement un problème avec la gestion des exceptions GCC 3.2. Par conséquent, le compilateur Intel ignore cette option lorsque GCC 3.2 est installé pour C++ et exception la manipulation est activée (valeur par défaut).

s'il vous Plaît être conscient que la citation ci-dessus n'est pertinente que pour les Intel C++ 15 compilateur, pas de GCC.

7
répondu Maxim Masiutin 2018-05-21 15:37:20