web-dev-qa-db-ja.com

C ++例外処理はどのようにマシンコードに変換されますか

精神的には、C++がコンパイルしてアセンブラーに変換するときに、try/throw/catchが舞台裏でどのように見えるのか常に疑問に思っていました。しかし、私はそれを使用したことがないので、それをチェックすることは決してありませんでした(一部の人々は怠惰と言うでしょう)。

通常のスタックはtrysを追跡するために使用されますか、それともこの目的のためだけに個別のスレッドごとのスタックが保持されますか? MSVCとg ++の間の実装は大きいですか、小さいですか?疑似asmを見せてください(IA-32も大丈夫です)ので、自分でチェックする必要はありません! :)

編集:これで、IA-32処理に関するMSVCの実装の基本を理解できました。 IA-32のg ++​​、またはその他のCPUについて知っている人はいますか?

編集2(11年後):ここ パフォーマンスに関するデータです。彼らはまた ソースコード を自由に利用できるようにしました。

41
Jonas Byström

MicrosoftJournalの「UndertheHood」シリーズは、1997年にその主題を詳細に調べました。

Win32™構造化例外処理の深さに関するクラッシュコース

10
Remy Lebeau

例外ハンドラーの不十分な実装try句が入力されると、ランタイムスタック上の各try句に対してある種の例外ハンドラーブロックをプッシュし、try句が終了するときにそれをポップします。最後にプッシュされた例外ハンドラブロックのアドレスを保持する場所も維持されます。通常、これらの例外ハンドラーはチェーン化されているため、最新バージョンから古いバージョンへのリンクをたどることで見つけることができます。例外が発生すると、最後にプッシュされたEHハンドラーブロックへのポインターが検出され、その「try」句のEHケースの処理がチェックされます。 EHケースがヒットすると、スタックのクリーンアップがプッシュされたEHのポイントに戻り、制御がEHケースに移ります。 EHにヒットがない場合、次のEHが検出され、プロセスが繰り返されます。 Windows 32ビットSEHスキームは、このバージョンです。

例外が発生しなくても、プログラムは各try句(プッシュしてからポップ)に対して実行時の価格を支払うため、これは不十分な実装です。

優れた実装では、try句が発生する範囲のテーブルを記録するだけです。これは、try句を開始/終了するためのオーバーヘッドがゼロであることを意味します。 (私の [〜#〜] parlanse [〜#〜] 並列プログラミング言語はこの手法を使用します)。例外は、テーブル内の例外ポイントのPCを検索し、テーブルによって選択されたEHに制御を渡します。 EHコードは、必要に応じてスタックをリセットします。速くてきれい。 Windows 64ビットEHはこのタイプだと思いますが、注意深く調べていません。

22
Ira Baxter

これは、このテーマに関する非常に貴重な記事です。 C++コンパイラが例外処理を実装する方法

16
AraK

C++標準委員会は、「C++パフォーマンス」に関するテクニカルレポートを公開し、C++機能がどのように速度を低下させるかについての多くの神話を暴きました。これには、例外処理の実装方法に関する詳細も含まれます。このテクニカルレポートの ドラフト は無料で入手できます。セクション5.4.1を確認してください。 「例外処理の実装の問題と手法」。

4
sellibitze

Asm from Godboltコンパイラエクスプローラー、g ++ 8.2のC +を使用したx86-64SystemV呼び出し規約+ ABI、キャッチする関数とスローする関数。

x86-64 SystemVはスタックアンワインドメタデータに.eh_frameセクションを使用するため、例外ヘルパーライブラリ関数はスタックをウォークしてレジスタを復元する方法を知っています。それが.cfiディレクティブが行うことです。

1
Peter Cordes

このドキュメント を見てください。これは例外処理の内部をかなりよく説明しています。

0
steve