__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で定義されています。

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

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


2
についてのヒントをありがとう-fno-exceptions。私CPPFLAGS += -fno-exceptionsはメイクファイルに追加し、それでエラーが解決しました。
Alan Kinnaman

12

例外処理の一部です。gcc EHメカニズムにより、さまざまなEHモデルを混在させることができ、パーソナリティルーチンが呼び出されて、例外が一致するかどうか、どのファイナライズを呼び出すかなどが決定されます。この特定のパーソナリティルーチンは、C ++例外処理用です(たとえば、gcj / Java例外処理)。


11

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

これはgcc、コードのコンパイルに使用する可能性があるためです。オプション-###を使用してコンパイルすると-lstdc++、リンカプロセスを呼び出すときにリンカオプションが欠落していることに気付くでしょう。でコンパイルするg++と、そのライブラリが含まれ、その中で定義されたシンボルが含まれます。


g ++でコンパイルする必要があるのは、コードがC ++であるとコンパイラーに明確に伝えたい場合のみであると常に思っていました(たとえば、拡張がありません)。現在、gccを使用してC ++コードをコンパイルすると、comeライブラリを含めることができないようです。一部のライブラリが欠落していることを除いてfile.cppgcc代わりにでコンパイルすると、他にいくつかの「副作用」がありg++ますか?
Lazer、

1
@eSkay私の知る限りでlibstdc++は、のリンクのみが2つの違いです。
Johannes Schaub-litb

6

libstd++コードベースの簡単なgrep により、次の2つの使用法が明らかになりました__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にジャンプし、segfaultが発生します。


必ずしも0にジャンプする必要はありません。グローバルは初期化されていないため、実際にはどのような値でもかまいません。
ストレージャー、2008年

6
strager、グローバルはプログラマーが初期化しない場合、ゼロで初期化されます
Johannes Schaub-litb '30

@litb:これは、カーネルがbssセクションのゼロ化を実装している場合にのみ当てはまります:-P。しかし、はい、それらは正気のために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.