web-dev-qa-db-ja.com

__gxx_personality_v0とは何ですか?

これはOS開発サイトからの中古の質問ですが、どこにもきちんとした説明が見つからなかったので、興味をそそられました。

Gccを使用して独立したC++プログラムをコンパイルおよびリンクすると、次のようなリンカーエラーが発生する場合があります。

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

これは明らかに、このシンボルはlibstdc ++で定義されているためです。libstdc++は独立した環境にはありません。問題を解決するには、このシンボルをどこかで定義する必要があります。

void *__gxx_personality_v0;

どちらがいいのですが、魔法のように機能するものが好きではありません。

93
Bruce Johnston

これは、スタック非表示テーブルで使用されます。これは、たとえば 別の質問への回答 のアセンブリ出力で確認できます。その答えで述べたように、その使用は Itanium C++ ABI で定義されており、 Personality Routine と呼ばれています。

グローバルなNULL voidポインターとして定義することで「機能する」のは、おそらく例外がスローされないためです。何かが例外をスローしようとすると、それが正しく動作しないことがわかります。

もちろん、例外を使用しているものがない場合は、-fno-exceptionsを使用して無効にすることができます(RTTIを使用していない場合は、-fno-rttiを追加することもできます)。それらを使用している場合は、(既に述べた他の回答として)gccの代わりにg++でリンクする必要があります。これにより-lstdc++が追加されます。

87
CesarB

これは例外処理の一部です。 gcc EHメカニズムにより、さまざまなEHモデルを混在させることができ、パーソナリティルーチンが呼び出されて、例外の一致、起動するファイナライズなどを決定します。この特定のパーソナリティルーチンは、Cgc例外処理)。

11

例外処理は、独立した実装に含まれています。

この理由は、おそらくgccを使用してコードをコンパイルするためです。オプション-###を指定してコンパイルすると、リンカープロセスを呼び出すときにリンカーオプション-lstdc++が欠落していることがわかります。 g++を指定してコンパイルすると、そのライブラリが含まれ、そのために定義されたシンボルが含まれます。

libstd++コードベースの簡単なgrepにより、__gx_personality_v0の次の2つの使用法が明らかになりました。

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にジャンプしてセグメンテーション違反が発生します。

6
Adam Rosenfield

私は一度このエラーがあり、Originを見つけました:

私はgccコンパイラを使用しており、C++プログラムではなくCプログラムを実行していたにもかかわらず、ファイルはCLIENT.Cと呼ばれていました。

gccは.C拡張をC++プログラムとして、.c拡張をCプログラムとして認識します(小さなCと大きなCに注意してください)。

そこで、ファイルの名前をCLIENT.cプログラムに変更しました。

6
jlguenego

上記の答えは正しいです。例外処理で使用されます。 GCCバージョン6の manual には詳細があります(バージョン7のマニュアルにはありません)。エラーは、GCCに不明なJava例外をスローする外部関数をリンクするときに発生する可能性があります。

2
sagitta