Hatena::ブログ(Diary)

ひっそりらぼ

2010-01-24

g++の例外処理(throw)の探検

11:46 |

最近、C++の仕組みについて興味が出てきた。今は、特に例外処理(try/catch)の所。

gcc(g++)のコードを落としてきて、ちょくちょく見ている。

そういえば、Binary Hacksにg++の例外処理の解説があったのを思い出した。今日は、HACK #38の「g++の例外処理を理解する(throw編)」を、久しぶりに起動したUbuntuで実験してみた。といっても、記事に書かれているコードをそのまま書き写して、g++でビルドして、確認したのと、記事からポイントされてたgccのコードをちょくっと見てみただけだけど。

以前は、g++では例外まわりのコード生成は、アセンブリでゴリゴリ生成されるものと思っていた。でもHACK #38をちゃんと読むとそうではないと。throwは、libstdc++(はじめて知った)にあるライブラリ関数を呼び出すことで実現していると。

それでthrowの核になるのは、__cxa_throwと。まだ全然理解できていないけど、throwがこのような関数呼び出しに置換されていることがわかっただけでも、収穫かな。例外を投げるにしても、構造体に色々データをセットアップしているだなんて、これまで全く知らなかったからなぁ。

gcc-4.4.3/libstdc++-v3/libsupc++/eh_throw.cc

extern "C" void
__cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo, 
			 void (*dest) (void *))
{
  // Definitely a primary.
  __cxa_refcounted_exception *header
    = __get_refcounted_exception_header_from_obj (obj);
  header->referenceCount = 1;
  header->exc.exceptionType = tinfo;
  header->exc.exceptionDestructor = dest;
  header->exc.unexpectedHandler = __unexpected_handler;
  header->exc.terminateHandler = __terminate_handler;
  __GXX_INIT_PRIMARY_EXCEPTION_CLASS(header->exc.unwindHeader.exception_class);
  header->exc.unwindHeader.exception_cleanup = __gxx_exception_cleanup;

#ifdef _GLIBCXX_SJLJ_EXCEPTIONS
  _Unwind_SjLj_RaiseException (&header->exc.unwindHeader);
#else
  _Unwind_RaiseException (&header->exc.unwindHeader);
#endif

  // Some sort of unwinding error.  Note that terminate is a handler.
  __cxa_begin_catch (&header->exc.unwindHeader);
  std::terminate ();
}

また時間がある時にでも探索できたらいいな。

トラックバック - http://d.hatena.ne.jp/fixme/20100124/1264301168