2008-11-30 8 views
79

Ceci est une question de seconde main d'un site de développement OS, mais il m'a fait curieux puisque je ne pouvais trouver une explication décente nulle part.À quoi sert __gxx_personality_v0?

Lors de la compilation et la liaison d'un programme C++ autonome en utilisant gcc, parfois une erreur de linker comme cela se produit:

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

C'est apparemment parce que ce symbole est défini dans libstdC++, ce qui manque dans un franco environnement permanent. La fixation du problème simplement, il faut définir ce symbole quelque part:

void *__gxx_personality_v0; 

Ce qui est agréable, mais je n'aime pas les choses qui fonctionnent comme par magie ... La question est, quel est le but de ce symbole?

Répondre

73

Il est utilisé dans les tables de non-distribution de la pile, que vous pouvez voir par exemple dans la sortie d'assemblage de my answer to another question. Comme mentionné sur cette réponse, son utilisation est définie par le Itanium C++ ABI, où il est appelé le Personality Routine. La raison pour laquelle cela "fonctionne" en le définissant comme un pointeur vide NULL global est probablement parce que rien ne lève une exception. Quand quelque chose essaie de lancer une exception, alors vous la verrez se conduire mal.

Bien sûr, si rien n'utilise d'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à mentionnées) lier avec g++ au lieu de gcc, ce qui va ajouter -lstdc++ pour vous.

+0

Merci pour le conseil à propos de '-fno-exceptions'. J'ai ajouté 'CPPFLAGS + = -fno-exceptions' à mon makefile, et cela a résolu l'erreur. –

10

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

4

A grep rapide de la base de code libstd++ révélé les deux usages suivants de __gx_personality_v0:

Dans libsupC++/dérouleur-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 ... 
} 

(Note: c'est en fait un peu plus compliqué que ça, 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 void* n'affectera rien, mais dès que cela se produit, vous allez planter - __gxx_personality_v0 est une fonction, non un objet global, donc essayer d'appeler la fonction va sauter à l'adresse 0 et provoquer une erreur de segmentation.

+0

Pas nécessairement de saut à 0; le global n'est pas initialisé donc ça pourrait être n'importe quelle valeur, vraiment. – strager

+6

strager, les globals sont initialisés à zéro si le programmeur ne les initialise pas –

+0

@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 0 initialisés pour l'amour de la santé mentale. –

8

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

La raison en est que vous utilisez éventuellement gcc pour 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. La compilation avec g++ inclura cette bibliothèque, et donc les symboles qui y sont définis.

+0

J'ai toujours pensé que compiler avec g ++ n'était nécessaire que lorsque vous vouliez dire au compilateur que le code était C++ (par exemple, extension manquante). Maintenant, il semble que la compilation de code C++ avec gcc manque l'inclusion de bibliothèques venir. En dehors de certaines bibliothèques manquantes, y a-t-il d'autres "effets secondaires" de la compilation de "fichier.cpp" avec "gcc" au lieu de "g ++"? – Lazer

+1

@eSkay autant que je sache, la liaison de 'libstdC++ 'est la seule différence entre les deux. –

4

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

Je travaillais avec un compilateur gcc et mon dossier a été appelé CLIENT.C malgré que je faisais un programme C et non un programme C++. Gcc reconnaît l'extension .C en tant que programme C++ et l'extension .c en tant que programme C (attention aux petits c et grands C).

J'ai donc renommé mon programme CLIENT.c et cela a fonctionné.

1

Les réponses ci-dessus sont correctes: elles sont utilisées dans la gestion des exceptions. Le manual pour GCC version 6 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 à GCC - déclenche des exceptions Java.

Questions connexes