À quoi sert __gxx_personality_v0?

103

C'est une question de seconde main d'un site de développement de système d'exploitation, mais cela m'a rendu curieux car je ne trouvais nulle part une explication décente.

Lors de la compilation et de la liaison d'un programme C ++ autonome à l'aide de gcc, une erreur de l'éditeur de liens comme celle-ci se produit parfois:

out/kernel.o:(.eh_frame+0x11): undefined reference to `__gxx_personality_v0'

Ceci est apparemment dû au fait que ce symbole est défini dans libstdc ++, qui manque dans un environnement autonome. Résoudre le problème nécessite simplement de définir ce symbole quelque part:

void *__gxx_personality_v0;

Ce qui est bien, mais je n'aime pas les choses qui fonctionnent comme par magie ... Alors la question est, quel est le but de ce symbole?

Bruce Johnston
la source

Réponses:

93

Il est utilisé dans la pile de tables déroulantes, que vous pouvez voir par exemple dans la sortie d'assemblage de ma réponse à une autre question . Comme mentionné dans cette réponse, son utilisation est définie par l' ABI Itanium C ++ , où elle est appelée routine de personnalité .

La raison pour laquelle il "fonctionne" en le définissant comme un pointeur vide global NULL est probablement parce que rien ne lève une exception. Lorsque quelque chose essaie de lancer une exception, vous verrez qu'elle se comporte mal.

Bien sûr, si rien n'utilise des exceptions, vous pouvez les désactiver avec -fno-exceptions(et si rien n'utilise RTTI, vous pouvez également ajouter -fno-rtti). Si vous les utilisez, vous devez (comme d'autres réponses déjà notées) créer un lien avec g++au lieu de gcc, ce qui ajoutera -lstdc++pour vous.

CesarB
la source
2
Merci pour le conseil à propos de -fno-exceptions. J'ai ajouté CPPFLAGS += -fno-exceptionsà mon makefile, et cela a résolu l'erreur.
Alan Kinnaman le
12

Cela fait partie de la gestion des exceptions. Le mécanisme gcc EH permet de mélanger divers modèles EH, et une routine de personnalité est appelée pour déterminer si une exception correspond, quelle finalisation appeler, etc. Cette routine de personnalité spécifique est pour la gestion des exceptions C ++ (par opposition à, disons, gcj / Java gestion des exceptions).

Martin c.Löwis
la source
11

La gestion des exceptions est incluse dans les implémentations autonomes.

La raison en est que vous utilisez éventuellement gccpour compiler votre code. Si vous compilez avec l'option, -###vous remarquerez qu'il manque l'option de l'éditeur de liens -lstdc++lorsqu'il appelle le processus de l'éditeur de liens. Compiler avec g++inclura cette bibliothèque, et donc les symboles qui y sont définis.

Johannes Schaub - litb
la source
J'ai toujours pensé que la compilation avec g ++ n'était nécessaire que lorsque vous vouliez spécifiquement dire au compilateur que le code était C ++ (par exemple, l'extension manquante). Maintenant, il semble que la compilation de code C ++ avec gcc manque l'inclusion des bibliothèques come. En dehors de quelques bibliothèques manquantes, y a-t-il d'autres "effets secondaires" de la compilation de mon file.cppavec gccau lieu de g++?
Lazer
1
@eSkay pour autant que je sache, la liaison de libstdc++est la seule différence entre les deux.
Johannes Schaub - litb
6

Un grep rapide de la libstd++base de code a révélé les deux utilisations suivantes de __gx_personality_v0:

Dans libsupc ++ / unwind-cxx.h

// GNU C++ personality routine, Version 0.                                      
extern "C" _Unwind_Reason_Code __gxx_personality_v0
     (int, _Unwind_Action, _Unwind_Exception_Class,
      struct _Unwind_Exception *, struct _Unwind_Context *);

Dans libsupc ++ / eh_personality.cc

#define PERSONALITY_FUNCTION    __gxx_personality_v0
extern "C" _Unwind_Reason_Code
PERSONALITY_FUNCTION (int version,
                      _Unwind_Action actions,
                      _Unwind_Exception_Class exception_class,
                      struct _Unwind_Exception *ue_header,
                      struct _Unwind_Context *context)
{
  // ... code to handle exceptions and stuff ...
}

(Remarque: c'est en fait un peu plus compliqué que cela; il y a une compilation conditionnelle qui peut changer certains détails).

Donc, tant que votre code n'utilise pas réellement la gestion des exceptions, définir le symbole comme void*n'affectera rien, mais dès que cela le fera, vous allez planter - __gxx_personality_v0est une fonction, pas un objet global, alors essayez pour appeler la fonction va sauter à l'adresse 0 et provoquer un segfault.

Adam Rosenfield
la source
Pas nécessairement sauter à 0; le global n'est pas initialisé donc il peut s'agir de n'importe quelle valeur, vraiment.
strager
6
strager, les globaux sont initialisés à zéro si le programmeur ne les initialise pas
Johannes Schaub - litb
@litb: ceci n'est vrai que si le noyau implémente la mise à zéro de la section bss :-P. Mais oui, ils devraient être initialisés à 0 pour des raisons de santé mentale.
Evan Teran
9
@Evan Teran: Non, une implémentation C conforme initialisera toujours les globaux à 0. Voir §5.1.2 et §6.7.8 paragraphe 10 de la norme C99.
Adam Rosenfield
6

J'ai eu cette erreur une fois et j'ai découvert l'origine:

J'utilisais un compilateur gcc et mon fichier a été appelé CLIENT.Calors que je faisais un programme C et non un programme C ++.

gcc reconnaît l' .Cextension en tant que programme C ++ et l' .cextension en tant que programme C (attention au petit c et au grand C).

J'ai donc renommé mon CLIENT.cprogramme de fichiers et cela a fonctionné.

jlguenego
la source
2

Les réponses ci-dessus sont correctes: elles sont utilisées dans la gestion des exceptions. Le manuel de la version 6 de GCC contient plus d'informations (qui ne sont plus présentes dans le manuel de la version 7). L'erreur peut survenir lors de la liaison d'une fonction externe qui - inconnue de GCC - lève des exceptions Java.

sagitta
la source