__gxx_personality_v0의 용도는 무엇입니까?


103

이것은 OS 개발 사이트의 간접 질문이지만 어디에서도 괜찮은 설명을 찾을 수 없기 때문에 궁금했습니다.

gcc를 사용하여 독립형 C ++ 프로그램을 컴파일하고 링크 할 때 때때로 다음과 같은 링커 오류가 발생합니다.

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

이 기호는 독립 환경에서 누락 된 libstdc ++에 정의되어 있기 때문입니다. 문제를 해결하려면이 기호를 어딘가에 정의하면됩니다.

void *__gxx_personality_v0;

어느 것이 좋지만 마법처럼 작동하는 것을 좋아하지 않습니다 ... 그래서 질문은,이 기호의 목적은 무엇입니까?

답변:


93

예를 들어 다른 질문에 대한 내 답변 의 어셈블리 출력에서 ​​볼 수있는 스택 언 위딩 테이블에서 사용됩니다 . 해당 답변에서 언급했듯이 사용은 Itanium C ++ ABI에 의해 정의되며 Personality Routine 이라고합니다 .

전역 NULL void 포인터로 정의하여 "작동"하는 이유는 예외가 발생하지 않기 때문일 것입니다. 무언가 예외를 던지려고하면 오작동하는 것을 보게 될 것입니다.

물론 예외를 사용하는 항목이 -fno-exceptions없으면를 사용하여 비활성화 할 수 있습니다 (RTTI를 사용하는 항목이 없으면을 추가 할 수도 있습니다 -fno-rtti). 그것들을 사용하는 경우, (이미 언급했듯이) g++대신 gcc추가 -lstdc++해야합니다.


2
에 대한 팁을 주셔서 감사합니다 -fno-exceptions. CPPFLAGS += -fno-exceptions내 makefile에 추가 했는데 오류가 해결되었습니다.
Alan Kinnaman

12

예외 처리의 일부입니다. gcc EH 메커니즘을 사용하면 다양한 EH 모델을 혼합 할 수 있으며 예외 일치 여부, 호출 할 최종화 등을 결정하기 위해 특성 루틴이 호출됩니다.이 특정 특성 루틴은 C ++ 예외 처리를위한 것입니다 (예 : gcj / Java 예외 처리).


11

예외 처리는 독립형 구현에 포함됩니다.

그 이유는 gcc코드를 컴파일 하는 데 사용할 수 있기 때문입니다 . 옵션으로 컴파일 하면 링커 프로세스를 호출 할 때 -###링커 옵션이 누락 된 것을 알 수 있습니다 -lstdc++. 로 컴파일 g++하면 해당 라이브러리와 그 안에 정의 된 기호가 포함됩니다.


저는 항상 g ++로 컴파일하는 것이 코드가 C ++ (예 : 확장 누락)임을 컴파일러에 알리고 싶을 때만 필요하다고 생각했습니다. 이제 gcc로 C ++ 코드를 컴파일하면 come 라이브러리가 포함되지 않는 것 같습니다. 일부 라이브러리가 누락 된 것 외에도 my file.cpp와 함께 컴파일 할 때의 다른 "부작용" gccg++있습니까?
Lazer

1
@ eSkay 내가 아는 한, 연결은 libstdc++둘 사이의 유일한 차이점입니다.
Johannes Schaub-litb

6

libstd++코드베이스 의 빠른 grep은 다음 두 가지 사용법을 보여줍니다 __gx_personality_v0.

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 *);

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

(참고 : 실제로는 그것보다 조금 더 복잡합니다. 일부 세부 사항을 변경할 수있는 조건부 컴파일이 있습니다).

따라서 코드가 실제로 예외 처리를 사용하지 않는 한, 심볼을 정의하는 void*것은 아무 영향도 미치지 않지만 즉시 충돌하게 될 것 __gxx_personality_v0입니다. 함수를 호출하면 주소 0으로 점프하여 세그 폴트가 발생합니다.


반드시 0으로 점프 할 필요는 없습니다. 글로벌은 초기화되지 않았으므로 실제로 어떤 값이 될 수 있습니다.
strager

6
strager, 전역은 프로그래머가 초기화하지 않으면 0으로 초기화됩니다
Johannes Schaub-litb

@litb : 이것은 커널이 bss 섹션 :-P를 0으로 구현하는 경우에만 해당됩니다. 그러나 예, 정상을 위해 0으로 초기화되어야합니다.
Evan Teran

9
@Evan Teran : 아니요, 준수하는 C 구현은 항상 전역을 0으로 초기화합니다. C99 표준의 §5.1.2 및 §6.7.8 단락 10을 참조하세요.
Adam Rosenfield

6

이 오류가 한 번 발생했고 출처를 찾았습니다.

나는 gcc 컴파일러를 사용 CLIENT.C하고 있었고 C ++ 프로그램이 아닌 C 프로그램을 수행하고 있음에도 불구하고 내 파일이 호출 되었습니다.

gcc는 .C확장을 C ++ 프로그램으로 인식하고 확장을 C 프로그램으로 인식합니다 .c(작은 C와 큰 C에주의).

그래서 파일 CLIENT.c프로그램의 이름을 바꾸었고 작동했습니다.


2

위의 답변은 정확합니다. 예외 처리에 사용됩니다. GCC 버전 6 의 매뉴얼 에 더 많은 정보가 있습니다 (버전 7 매뉴얼에는 더 이상 존재하지 않음). GCC에 알려지지 않은 외부 함수를 연결할 때 오류가 발생할 수 있으며 Java 예외가 발생합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.