2008-11-30 7 views
79

Esta es una pregunta de segunda mano de un sitio de desarrollo de sistema operativo, pero me dio curiosidad ya que no pude encontrar una explicación decente en ninguna parte.¿Para qué es __gxx_personality_v0?

Al compilar y vincular un programa independiente C++ utilizando gcc, a veces un error enlazador como se produce esto:

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

Esto es aparentemente debido a este símbolo se define en libstdC++, que está ausente en un free- entorno de pie Solucionar el problema simplemente requiere definir este símbolo en alguna parte:

void *__gxx_personality_v0; 

lo cual es bueno, pero no me gustan las cosas que simplemente funcionan mágicamente ... Así que la pregunta es, ¿cuál es el propósito de este símbolo?

Respuesta

73

Se utiliza en las tablas de pila inestables, que se puede ver, por ejemplo, en la salida de ensamblaje my answer to another question. Como se menciona en esa respuesta, su uso está definido por el Itanium C++ ABI, donde se llama Personality Routine.

La razón por la que "funciona" al definirlo como un puntero nulo mundial es probablemente porque nada arroja una excepción. Cuando algo trata de lanzar una excepción, entonces verá que se porta mal. Por supuesto, si nada está usando excepciones, puede deshabilitarlas con -fno-exceptions (y si nada está usando RTTI, también puede agregar -fno-rtti). Si los está utilizando, tiene que (como otras respuestas ya indicadas) vincular con g++ en lugar de gcc, que agregará -lstdc++ para usted.

+0

Gracias por el consejo sobre '-fno-excepciones'. Agregué 'CPPFLAGS + = -fno-exceptions' a mi archivo MAKE, y eso resolvió el error. –

10

Es parte del manejo de excepciones. El mecanismo gcc EH permite mezclar varios modelos EH, y se invoca una rutina de personalidad para determinar si coincide una excepción, qué finalización invocar, etc. Esta rutina de personalidad específica es para el manejo de excepciones C++ (en oposición a, digamos, gcj/Java manejo de excepciones).

4

A grep rápida de la base de código libstd++ reveló los siguientes dos usos de __gx_personality_v0:

En libsupC++/desenrollado-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 *); 

En 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: en realidad es un poco más complicado que eso, hay una compilación condicional que puede cambiar algunos detalles).

Por lo tanto, el tiempo que su código no lleve a la práctica el manejo de excepciones, que define el símbolo como void* no afectará nada, pero tan pronto como lo hace, va a chocar - __gxx_personality_v0 es una función, no algún objeto global, por lo que intentar llamar a la función va a saltar a la dirección 0 y provocar una segfault.

+0

No necesariamente saltar a 0; lo global no está inicializado, por lo que podría tener algún valor, realmente. – strager

+6

strager, los valores globales se inicializan en cero si el programador no los inicializa –

+0

@litb: esto solo es cierto si el kernel implementa la puesta a cero de la sección bss :-P. Pero sí, deberían inicializarse por motivos de cordura. –

8

El manejo de excepciones se incluye en implementaciones independientes.

La razón de esto es que posiblemente use gcc para compilar su código. Si compila con la opción -###, notará que le falta la opción del vinculador -lstdc++ cuando invoca el proceso del enlazador. La compilación con g++ incluirá esa biblioteca y, por lo tanto, los símbolos definidos en ella.

+0

Siempre pensé que compilar con g ++ solo era necesario cuando específicamente querías decirle al compilador que el código era C++ (por ejemplo, faltaba una extensión). Ahora parece que la compilación del código C++ con gcc omite la inclusión de las bibliotecas come. Además de faltar algunas bibliotecas, ¿hay algún otro "efecto secundario" de compilación de mi 'archivo.cpp' con' gcc' en lugar de 'g ++'? – Lazer

+1

@eSkay hasta donde yo sé, la vinculación de 'libstdC++' es la única diferencia entre los dos. –

4

tuve este error una vez y descubrí el origen:

que estaba usando un compilador gcc y mi archivo llamaron CLIENT.C pesar de que estaba haciendo un programa en C y no un programa en C++.

gcc reconoce la extensión .C como programa C++ y la extensión .c como programa C (tenga cuidado con la C pequeña y la C grande).

Así que renombré mi archivo CLIENT.c y funcionó.

1

Las respuestas anteriores son correctas: se utiliza en el manejo de excepciones. El manual para GCC versión 6 tiene más información (que ya no está presente en el manual de la versión 7). El error puede surgir cuando se vincula una función externa que, desconocida para GCC, arroja excepciones Java.