编译器是如何实现 try ... catch 的?

demonstrate 发表于 2006-10-27 14:30:44

下面有这么一段 C++ 代码:
#include <iostream>

using namespace std ;

class A {
public:
  A() {
  }
} ;

void
f( void )
{
  throw A( ) ;
}

int
main( int argc, char *argv[] )
{
  try {
    f( ) ;
  }
  catch( A &e ) {
    cout << "Exception occured!" << endl ;
  }

  return 0 ;
}
这是汇编的结果,我们仔细研究一下 GCC 怎么完成的 try catch 功能。
00401414 <_main>:
401414: 55 push %ebp
401415: 89 e5 mov %esp,%ebp
401417: 57 push %edi
401418: 56 push %esi
401419: 53 push %ebx
40141a: 83 ec 5c sub 0x5c,%esp
40141d: 83 e4 f0 and 0xfffffff0,%esp
401420: b8 00 00 00 00 mov 0x0,%eax
401425: 83 c0 0f add 0xf,%eax
401428: 83 c0 0f add 0xf,%eax
40142b: c1 e8 04 shr 0x4,%eax
40142e: c1 e0 04 shl 0x4,%eax
401431: 89 45 a8 mov %eax,0xffffffa8(%ebp)
401434: 8b 45 a8 mov 0xffffffa8(%ebp),%eax
401437: e8 84 c8 00 00 call 40dcc0 <___chkstk>
40143c: c7 45 d4 e0 19 40 00 movl 0x4019e0,0xffffffd4(%ebp)
401443: c7 45 d8 6c b8 43 00 movl 0x43b86c,0xffffffd8(%ebp)
40144a: 8d 45 dc lea 0xffffffdc(%ebp),%eax
40144d: 8d 55 f4 lea 0xfffffff4(%ebp),%edx
401450: 89 10 mov %edx,(%eax)
401452: ba d1 14 40 00 mov 0x4014d1,%edx
401457: 89 50 04 mov %edx,0x4(%eax)
40145a: 89 60 08 mov %esp,0x8(%eax)
40145d: 8d 45 bc lea 0xffffffbc(%ebp),%eax
401460: 89 04 24 mov %eax,(%esp)
401463: e8 08 be 00 00 call 40d270 <__Unwind_SjLj_Register>
401468: e8 63 b9 00 00 call 40cdd0 <___main>
40146d: c7 45 c0 02 00 00 00 movl 0x2,0xffffffc0(%ebp)
401474: e8 65 ff ff ff call 4013de <__Z1fv>
401479: e9 92 00 00 00 jmp 401510 <_main+0xfc>
40147e: 83 7d ac 01 cmpl 0x1,0xffffffac(%ebp)
401482: 74 12 je 401496 <_main+0x82>
401484: 8b 45 b4 mov 0xffffffb4(%ebp),%eax
401487: 89 04 24 mov %eax,(%esp)
40148a: c7 45 c0 ff ff ff ff movl 0xffffffff,0xffffffc0(%ebp)
401491: e8 9a c4 00 00 call 40d930 <__Unwind_SjLj_Resume>
401496: 8b 55 b4 mov 0xffffffb4(%ebp),%edx
401499: 89 14 24 mov %edx,(%esp)
40149c: e8 0f 2d 00 00 call 4041b0 <___cxa_begin_catch>
4014a1: 89 45 f0 mov %eax,0xfffffff0(%ebp)
4014a4: c7 44 24 04 00 e0 43 movl 0x43e000,0x4(%esp)
4014ab: 00
4014ab: 00
4014ac: c7 04 24 c0 13 44 00 movl 0x4413c0,(%esp)
4014b3: c7 45 c0 01 00 00 00 movl 0x1,0xffffffc0(%ebp) EERSt13basic_ostreamIcT_ES5_PKc>
4014bf: c7 44 24 04 70 8c 43 movl 0x438c70,0x4(%esp)
4014c6: 00
4014c7: 89 04 24 mov %eax,(%esp)
4014ca: e8 49 74 02 00 call 428918 <__ZNSolsEPFRSoS_E>
4014cf: eb 3a jmp 40150b <_main+0xf7>
4014d1: 8d 6d 0c lea 0xc(%ebp),%ebp
4014d4: 8b 45 c0 mov 0xffffffc0(%ebp),%eax
4014d7: 8b 55 c4 mov 0xffffffc4(%ebp),%edx
4014da: 89 55 b4 mov %edx,0xffffffb4(%ebp)
4014dd: 8b 55 c8 mov 0xffffffc8(%ebp),%edx
4014e0: 89 55 ac mov %edx,0xffffffac(%ebp)
4014e3: 83 f8 01 cmp 0x1,%eax
4014e6: 74 96 je 40147e <_main+0x6a>
4014e8: 8b 45 b4 mov 0xffffffb4(%ebp),%eax
4014eb: 89 45 b0 mov %eax,0xffffffb0(%ebp)
4014ee: e8 cd 2d 00 00 call 4042c0 <___cxa_end_catch>
4014f3: 8b 55 b0 mov 0xffffffb0(%ebp),%edx
4014f6: 89 55 b4 mov %edx,0xffffffb4(%ebp)
4014f9: 8b 45 b4 mov 0xffffffb4(%ebp),%eax
4014fc: 89 04 24 mov %eax,(%esp)
4014ff: c7 45 c0 ff ff ff ff movl 0xffffffff,0xffffffc0(%ebp)
401506: e8 25 c4 00 00 call 40d930 <__Unwind_SjLj_Resume>
40150b: e8 b0 2d 00 00 call 4042c0 <___cxa_end_catch>
401510: c7 45 b8 00 00 00 00 movl 0x0,0xffffffb8(%ebp)
401517: 8d 45 bc lea 0xffffffbc(%ebp),%eax
40151a: 89 04 24 mov %eax,(%esp)
401522: 8b 45 b8 mov 0xffffffb8(%ebp),%eax
401525: 8d 65 f4 lea 0xfffffff4(%ebp),%esp
401528: 5b pop %ebx
401529: 5e pop %esi
40152a: 5f pop %edi
40152b: 5d pop %ebp
40152c: c3 ret
40152d: 90 nop
现在看不懂啊... 下面是 f 的汇编代码
004013de <__Z1fv>:
4013de: 55 push %ebp
4013df: 89 e5 mov %esp,%ebp
4013e1: 53 push %ebx
4013e2: 83 ec 14 sub #CONTENT#x14,%esp
4013e5: c7 04 24 01 00 00 00 movl #CONTENT#x1,(%esp)
4013ec: e8 2f 2b 00 00 call 403f20 <___cxa_allocate_exception>
4013f1: 89 c3 mov %eax,%ebx
4013f3: 89 1c 24 mov %ebx,(%esp)
4013f6: e8 65 f7 00 00 call 410b60 <__ZN1AC1Ev>
4013fb: c7 44 24 08 00 00 00 movl #CONTENT#x0,0x8(%esp)
401402: 00
401403: c7 44 24 04 ec ee 43 movl #CONTENT#x43eeec,0x4(%esp)
40140a: 00
40140b: 89 1c 24 mov %ebx,(%esp)
40140e: e8 1d 2a 00 00 call 403e30 <___cxa_throw>
401413: 90 nop
注意到 f 简单到一句话,可见 throw 本身实现起来是需要一定的技巧的。首先在 4013ec 部分
call 的函数式编译器产生的,其中 ms 传入了一个参数,也就是 4013e5 那句 movl 传的 1 。
之后 4013f6 处 call 的是 A 的构造函数,传入的参数来自于 EAX,但是实际上我们的构造函数
并没有参数。最后 40140e 处 call 的也是编译器自己产生的函数,带有三个参数,4013fb 处的
0x0 和 401403 处的 0x43eeec,还有寄存器 EBX 的内容,这使得我们必须看看 ___cxa_allocate_exception
产生了什么放在 EAX 中传回...

注意,因为 exception 是编译器实现不同的,因此这部分不能推广到其他的编译器上。
关键词(Tag): c++ catch try

曾经的这一天...


收藏: QQ书签 del.icio.us 订阅: Google 抓虾

最新评论


  • Gambol
    2006-10-28 05:56:04

    师父徒弟没有学编译原理,以后怎么混啊……


  • demonstrate
    2006-10-28 09:12:24

    师父,try catch 到底在干什么啊!!


  • wshxzt
    2006-10-28 22:55:23

    寒……想到上学期计算机原理那个反汇编的project了……痛苦的回忆啊


  • demonstrate
    2006-10-28 23:13:52

    大牛啊,仰仗您给我做个解释了!!!

发表评论

* 昵称

已经注册过? 请登录

新用户请先注册 以便能显示头像及追踪评论回复

Email
网址
* 评论
表情
 
 

分类小组论坛
杂谈, 娱乐、八卦, 文学、艺术, 体育, 旅游、同城, 象牙塔, 情感, 时尚、生活, 星座, 科技

请注意遵守中华人民共和国法律法规, 如威胁到本站生存, 将依法向有关部门报告, 同时本站的相关记录可能成为对您不利的证据.

相关法律法规
全国人大常委会关于维护互联网安全的决定
中华人民共和国计算机信息系统安全保护条例
中华人民共和国计算机信息网络国际联网管理暂行规定
计算机信息网络国际联网安全保护管理办法
计算机信息系统国际联网保密管理规定