使った資料置いときます。
http://morihyphen.hp.infoseek.co.jp/g++eh/page.html
宣伝が邪魔なら
http://morihyphen.hp.infoseek.co.jp/g++eh/b20-g++eh.zip


ネタばらし、というのを嫌う人もいるらしいのだけど、僕はそういうのを書いたり読んだりするのが好きなんで適当に。


ここ何年か、ネタをやる度に失敗し続けてたので、「こんなネタでいいのか…?」とか、非常に心配だったんだけど、会場の雰囲気が良かったので、まあなんとかなった。
プロジェクタに映らなかったのは謎。マウスの挙動を見る限りウィンドウは出てたように見えたんだけど。結局あれはWindowsで。屈辱。
クールビズは当日の朝思い付いた。「w_oは非推奨です」をやる予定だったんだけど、微妙だと思ってたのでクールビズを採用。
「とゆーのは全部嘘です」は最初に思い付いたネタだったかな…あー、「キャッチボールはできません」のほうが先だったかもしれない。
僕には説明できないので適当に飛ばしたとこその1。「unwindは何」の「色々仕組み」。
コードをちょびちょび説明するのをどうしようかな…って悩んでたんだけど、方法を思い付かなかったので「読めません」。で済ますことに。
僕には説明できないので適当に飛ばしたとこその2。DWARF2全体的に。
プログラミング言語DWARF2は外部との入出力の部分が非常に弱いので、そこらへんが厳しい…かもしれない。
「Cで捕まえる」のコードは、

extern void throw_func( void );

void func()
{
  asm(".region_begin:");
  throw_func();
  asm(".region_end:");

  puts("kokoniha konai");

  asm(".handler_begin:");
  puts("catch!!!!");
  asm(".handler_end:");
}
asm(".func_end:");


asm("\t\n"
    "\t.size	_Z5func3v, .-_Z5func3v\n"
    "\t.section	.gcc_except_table\n"
    "\t.align 4\n"
    ".func_lsda:\n"
    "\t.byte	0xff	# @LPStart format (omit)\n"
    "\t.byte	0x0	# @TType format (absolute)\n"
    "\t.uleb128 .ttd_end - .ttd_start	# @TType base offset\n"

    ".ttd_start:\n"
    "\t.byte	0x1	# call-site format (uleb128)\n"
    "\t.uleb128 .call_site_end-.call_site_begin	# Call-site table length\n"

    ".call_site_begin:\n"
    "\t.uleb128 .region_begin - func	# region 0 start\n"
    "\t.uleb128 .region_end-.region_begin	# length\n"
    "\t.uleb128 .handler_begin - func	# landing pad\n"
    "\t.uleb128 0x1	# action\n"
    ".call_site_end:\n"

    "\t.byte	0x1	# Action record table\n"
    "\t.byte	0x0\n"
    "\t.align 4\n"
    "\t.long	_ZTIi\n"
    ".ttd_end:\n"
    "\t\n");

__asm__ (
	 "\t.section .eh_frame, \"a\", @progbits\n"
	 "\t.cie:\n"
	 "\t.long .cie_end-.cie_begin\n"

	 "\t.cie_begin:\n"
	 "\t.long 0\n"
	 "\t.byte 1\n"
	 "\t.ascii \"zPL\\0\"	# CIE Augmentation\n"
	 "\t.uleb128 1\n"
	 "\t.sleb128 -4\n"
	 "\t.byte 8\n"
	 "\t.uleb128 0x6	# Augmentation size\n"
	 "\t.byte	0x0	# Personality (absolute)\n"
	 "\t.long	__gxx_personality_v0\n"
	 "\t.byte	0x0	# LSDA Encoding (absolute)\n"

	 "\t.uleb128 0\n"
	 "\t.byte	0xc	# DW_CFA_def_cfa\n"
	 "\t.uleb128 0x4\n"
	 "\t.uleb128 0x4\n"
	 "\t.byte	0x88	# DW_CFA_offset, column 0x8\n"
	 "\t.uleb128 0x1\n"

	 "\t.align 4\n"
	 "\t.cie_end:\n"
);
__asm__ (
	 ".fde:\n"
	 "\t.long .fde_end-.fde_begin\n"

	 ".fde_begin:\n"
	 "\t.long .fde_begin-.cie\n"
	 "\t.long func\n"
	 "\t.long .func_end - func\n"
	 "\t.uleb128 0x4	# Augmentation size\n"
	 "\t.long	.func_lsda	# Language Specific Data Area\n"

	 "\t.byte	0xe	# DW_CFA_def_cfa_offset\n"
	 "\t.uleb128 0x8\n"
	 "\t.byte	0x85	# DW_CFA_offset, column 0x5\n"
	 "\t.uleb128 0x2\n"
	 "\t.byte	0xd	# DW_CFA_def_cfa_register\n"
	 "\t.uleb128 0x5\n"
	 "\t.align 4\n"
	 "\t.fde_end:\n");

こんな感じ。__asm__はCじゃないとか(Cだとラベル間のオフセットが定数にならない)。スタティックリンクじゃないと動かない(何故)とか。後始末をちゃんとしてないとか。投げたオブジェクトはリーク。


あんな大人数の前で喋ったの始めて…とか思ったけど、中学生のときに、なんか、そんなことがあったような。あれは嫌な思い出に近いけど。

今確認したことをいくつか。


C++の関数からCの関数呼んで、さらにそこからC++の関数を呼んだ場合、要するに間にC関数を挟んだ場合、例外は投げられない、と、確認せずに適当に言ったのが少し不安だったのだけど、間違ってなかったので安心。
いやー、でも、こういうのって、問題にならないのかな…。コールバックとか使ってたら問題になりそうなんだけど。危険そうだから、という理由で、無意識のうちに避けてしまっているのかもしれない。C++仕様ではどうなってるのかな…


お。こんなオプションが。

  -funwind-tables         巻き戻しを行なう例外補足用テーブルを生成する


あと、継承関係があるときのcatch判定は、魔術等は全然無くて、type_infoで地道に判定してるように見えます。これの効率は…ちょっとわからないですが。