A cosa serve __gxx_personality_v0?


103

Questa è una domanda di seconda mano da un sito di sviluppo del sistema operativo, ma mi ha incuriosito poiché non sono riuscito a trovare una spiegazione decente da nessuna parte.

Durante la compilazione e il collegamento di un programma C ++ indipendente utilizzando gcc, a volte si verifica un errore del linker come questo:

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

Questo è apparentemente perché questo simbolo è definito in libstdc ++, che manca in un ambiente indipendente. La risoluzione del problema richiede semplicemente la definizione di questo simbolo da qualche parte:

void *__gxx_personality_v0;

Il che è carino, ma non mi piacciono le cose che funzionano magicamente ... Quindi la domanda è: qual è lo scopo di questo simbolo?

Risposte:


93

Viene utilizzato nelle tabelle a scomparsa dello stack, che puoi vedere ad esempio nell'output dell'assembly della mia risposta a un'altra domanda . Come accennato in quella risposta, il suo utilizzo è definito dall'Itanium C ++ ABI , dove viene chiamato Personality Routine .

Il motivo per cui "funziona" definendolo come un puntatore void NULL globale è probabilmente perché nulla genera un'eccezione. Quando qualcosa cerca di lanciare un'eccezione, vedrai che si comporta male.

Ovviamente, se niente usa eccezioni, puoi disabilitarle con -fno-exceptions(e se niente sta usando RTTI, puoi anche aggiungere -fno-rtti). Se li stai usando, devi (come altre risposte già notato) collegare con g++invece di gcc, che si aggiungerà -lstdc++per te.


2
Grazie per il suggerimento -fno-exceptions. Ho aggiunto CPPFLAGS += -fno-exceptionsal mio makefile e questo ha risolto l'errore.
Alan Kinnaman

12

Fa parte della gestione delle eccezioni. Il meccanismo EH di gcc consente di combinare vari modelli EH e viene invocata una routine di personalità per determinare se un'eccezione corrisponde, quale finalizzazione invocare, ecc. Questa routine di personalità specifica è per la gestione delle eccezioni C ++ (al contrario, diciamo, di gcj / Java la gestione delle eccezioni).


11

La gestione delle eccezioni è inclusa nelle implementazioni indipendenti.

La ragione di ciò è che potresti usare gccper compilare il tuo codice. Se compili con l'opzione -###noterai che manca l'opzione linker -lstdc++quando richiama il processo linker. La compilazione con g++includerà quella libreria, e quindi i simboli in essa definiti.


Ho sempre pensato che la compilazione con g ++ fosse necessaria solo quando si desiderava specificamente dire al compilatore che il codice era C ++ (ad esempio, estensione mancante). Ora sembra che la compilazione del codice C ++ con gcc non includa le librerie come. A parte la mancanza di alcune librerie, ci sono altri "effetti collaterali" della compilazione di my file.cppcon gccinvece di g++?
Lazer

1
@eSkay per quanto ne so, il collegamento di libstdc++è l'unica differenza tra i due.
Johannes Schaub - litb

6

Un rapido grep della libstd++base di codice ha rivelato i seguenti due utilizzi di __gx_personality_v0:

In libsupc ++ / unfind-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 *);

In 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 ...
}

(Nota: in realtà è un po 'più complicato di così; c'è qualche compilazione condizionale che può cambiare alcuni dettagli).

Quindi, fintanto che il tuo codice non utilizza effettivamente la gestione delle eccezioni, definire il simbolo come void*non influirà su nulla, ma non appena lo farà, andrai in crash - __gxx_personality_v0è una funzione, non un oggetto globale, quindi provare per chiamare la funzione si salterà all'indirizzo 0 e causerà un segfault.


Non necessariamente saltare a 0; il valore globale non è inizializzato quindi potrebbe essere qualsiasi valore, davvero.
strager il

6
strager, le variabili globali vengono inizializzate a zero se il programmatore non le inizializza
Johannes Schaub - litb

@litb: questo è vero solo se il kernel implementa l'azzeramento della sezione bss :-P. Ma sì, dovrebbero essere 0 inizializzati per motivi di sanità mentale.
Evan Teran

9
@Evan Teran: No, un'implementazione C conforme inizializzerà sempre le globali a 0. Vedere §5.1.2 e §6.7.8 paragrafo 10 dello standard C99.
Adam Rosenfield,

6

Ho avuto questo errore una volta e ho scoperto l'origine:

Stavo usando un compilatore gcc e il mio file è stato chiamato CLIENT.Cnonostante stessi facendo un programma C e non un programma C ++.

gcc riconosce l' .Cestensione come programma C ++ e l' .cestensione come programma C (fare attenzione al C piccolo e C grande).

Quindi ho rinominato il mio CLIENT.cprogramma file e ha funzionato.


2

Le risposte sopra sono corrette: viene utilizzato nella gestione delle eccezioni. Il manuale per GCC versione 6 ha più informazioni (che non è più presente nel manuale versione 7). L'errore può verificarsi quando si collega una funzione esterna che, sconosciuta a GCC, genera eccezioni Java.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.