例外
とある機会に謎の人から、「なぜMonaではC++の例外機構が使えないのか?使えるようにした方が良いのではないか?」とご指摘を頂きました。
たしかにMonaで動くアプリケーションはg++のオプションである -fno-exception を使用して例外機構を使用しないようにコンパイルしなければいけません。
なぜMonaで例外が使えないか?
- 例外をずっとオフにしていて特に気にしていなかった。
- 例外をサポートをするのは難しそうだ。(カーネルのサポートが必要との噂)
というわけなので久しぶりにまじめな技術的な話題へと突入。
敵を知ることから始めようということで、g++@cygwinに簡単な例外のコードを食わせてみます。
class Hoge { }; int main(int argc, char *argv[]) { throw Hoge(); return 0; }
- Sオプションでの出力抜粋はこんな感じ。
〜略〜 call __alloca call ___main movl $1, (%esp) call ___cxa_allocate_exception L2: movl $0, 8(%esp) movl $__ZTI4Hoge, 4(%esp) movl %eax, (%esp) call ___cxa_throw 〜略〜 __ZTS4Hoge: .ascii "4Hoge\0" .def ___cxa_throw; .scl 3; .type 32; .endef .def ___cxa_allocate_exception; .scl 3; .type 32; .endef
ふむ。___cxa_allocate_exceptionで例外オブジェクト作成して、___cxa_throwで throw しているようですね。
Googleで調べたところ、二つの関数はlibstdc++で定義・実装されているようです。
- __cxa_allocate_exceptionは
- eh_alloc.ccで定義されている。要約するとstd::mallocで領域を確保しているだけっぽい。
-
- eh_throw.ccで定義されている。std:terminateが更に呼び出されて・・・。うーむ分からなくなってきた。
さていろいろ調べたら同じはてなダイアリー内に例外について詳しく書いている記事を見つけた。
id:yupo5656:20040808:p2
非常に分かりやすい。更にリンク元のサイト(英文)http://www.codeproject.com/cpp/Exceptionhandler.aspを読めば例外の仕組みが分かる。
ざっと読んだ感じだとカーネルの助けはいらないかなぁという印象を受けた。
例外発生時にスタック(と事前に生成したテーブル)を辿っていくだけっぽい。
ちなみにid:yupo5656:20040808:p2で説明されている
このときコンパイラは、 (X, 掃除コードのアドレス) の組をテーブル化してオブジェクトコードに埋めておく。「掃除コード」もコンパイラが生成したもので、具体的には「bar()呼び出し中に例外が throwされた場合に行わなければならない処理(foo()内でスタックに置いたオブジェクトのデストラクタ呼びなど)」が書かれる。こういうコードは g++ -S でアセンブリリストを吐かせれば目視で確認できる。
は
int main(int argc, char *argv[]) { try { throw Hoge(); } catch (Hoge e) { } return 0; }
をコンパイルした結果でみる事ができる。
〜略〜 .section .gcc_except_table,"dr" .align 4 LLSDA112: .byte 0xff .byte 0x0 .uleb128 LLSDATT112-LLSDATTD112 LLSDATTD112: .byte 0x1 .uleb128 LLSDACSE112-LLSDACSB112 LLSDACSB112: 〜略〜
というわけで、libstdc++の例外関係の一部のコードを移植すればMonaでも例外が使えるかもしれないというのが今日のところの結論。
ちなみにVC++は別の方法で例外を実装しているらしいですがまだちゃんとドキュメントを読んでいません。
※ここの話題はMonaに例外機構を組み込むのを目的としたものではありません。単なる技術的興味で書いたネタです。