C_and_CPP 板


LINE

c++ exception handling 还真不是普通的复杂, 我目前仅仅知道其实作原理, 但实作细 节太复杂, 没能搞懂。 vc 和 gcc 有不同的作法, 我研究的是 gcc 的作法。 看了不少参考资料, 这篇文章以 binary hacks 繁体中文版 item 38, 39, 40, 41 为 主, 因为有个小程式可以用来实验以及说明 exception handle。 下面这 3 个函式是最主要的关键: 1 __cxa_throw 2 _Unwind_RaiseException 3 __gxx_personality_v0 (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) 这些函式的 source code 在 gcc libgcc 目录下, libgcc 是一个很神秘的 library, 里 头几乎是 gcc 特异功能的实做。unwind, 软体浮点数 ... 都是在这里。 gcc-3.4.4/gcc gcc-5.4.0/libgcc _Unwind_SjLj_RaiseException gcc-5.4.0/libgcc/unwind-sjlj.c _Unwind_RaiseException gcc-5.4.0/libgcc/unwind.inc #define PERSONALITY_FUNCTION __gxx_personality_v0 PERSONALITY_FUNCTION (int version, _Unwind_Action actions, _Unwind_Exception_Class exception_class, struct _Unwind_Exception *ue_header, struct _Unwind_Context *context) /gcc-5.4.0/libstdc++-v3/libsupc++/eh_personality.cc __cxa_throw extern "C" void __cxxabiv1::__cxa_throw (void *obj, std::type_info *tinfo, void (_GLIBCXX_CDTOR_CALLABI *dest) (void *)) gcc-5.4.0/libstdc++-v3/libsupc++/eh_throw.cc a.cpp L116 throw 100; 会转成呼叫 (ref a.cpp L118 ~ 120) __cxa_allocate_exception() __cxa_throw() __cxa_throw() 发动时的流程: __cxxabiv1::__cxa_throw -> 执行的是 _Unwind_SjLj_RaiseException #ifdef _GLIBCXX_SJLJ_EXCEPTIONS _Unwind_SjLj_RaiseException (&header->exc.unwindHeader); #else _Unwind_RaiseException (&header->exc.unwindHeader); #endif | | |-> __gxx_personality_sj0 | | |-> uw_install_context uw_install_context 会呼叫 longjmp 回到上一个函式, 以 a.cpp 来说, 就是 func1()。 __gxx_personality_sj0 是干麻用的? 搜寻是不是有对应的 catch statement, 或是有那 个物件需要解构, 得去执行解构函式, 像 func1() 有个物件需要解构, __gxx_personality_sj0 知道这件事情, 所以才要让 _Unwind_RaiseException 往 func1 跳, 很神奇是吧! 一但 func1() 拿掉 a.cpp L128 那个 Obj obj, 就不会跳回 func1()。 bt.cpp 只有模拟一半的功能, 使用 setjmp/longjmp, back_to_func 可以回到前一个 function, sjlj 就是用类似的方法串起这些 jmp_buf; 不过我不知道怎麽使用 .eh_frame, .gcc_except_table section 里头的资料来得知是不是有那个解构函式需要 执行, 是不是有符合的 catch statement。 bt.cpp 1 #include <setjmp.h> 2 #include <string> 3 #include <map> 4 5 using namespace std; 6 7 map<string, jmp_buf> stack_frame; 8 9 void back_to_func(const string &fn) 10 { 11 //jmp_buf frame = stack_frame[fn]; 12 //stack_frame[fn]; 13 longjmp(stack_frame[fn], 5); 14 } 15 16 void f3() 17 { 18 printf("in f3\n"); 19 back_to_func("f2"); 20 } 21 22 void f2() 23 { 24 jmp_buf frame; 25 int ret = setjmp(frame); 26 if (ret == 0) 27 { 28 stack_frame.insert({"f2", frame}); 29 f3(); 30 } 31 else 32 { 33 printf("back to f2\n"); 34 back_to_func("f1"); 35 } 36 } 37 38 void f1() 39 { 40 jmp_buf frame; 41 int ret = setjmp(frame); 42 if (ret == 0) 43 { 44 stack_frame.insert({"f1", frame}); 45 f2(); 46 } 47 else 48 { 49 printf("back to f1\n"); 50 back_to_func("main"); 51 } 52 } 53 54 int main(int argc, char *argv[]) 55 { 56 jmp_buf frame; 57 int ret = setjmp(frame); 58 if (ret == 0) 59 { 60 stack_frame.insert({"main", frame}); 61 f1(); 62 } 63 else 64 { 65 printf("back to main\n"); 66 } 67 printf("end main\n"); 68 return 0; 69 } binary hacks 繁体中文版 item 38, 39, 40, 41 是用 gcc 3.4.4 讲解, 虽然过时了, 但基本原理是一样的, 就先从 gcc 3.4.4 的建构开始吧。 g++ 使用 setjmp/longjmp, dwarf 这两种来支援 c++ exception handle, 目前的 gcc 5 似乎不使用 --enable-sjlj-exceptions, 我比较熟悉 setjmp/longjmp 的作法, dwarf2 太苦了, 我不想走这条路, 先以 --enable-sjlj-exceptions 来建构 gcc 3.4.4 。 我以熟悉的 setjmp/long 来学习, 编译 gcc 3.4.4 加上 --enable-sjlj-exceptions, 即使用以 setjmp/longjmp 实做的 exception handle。 setjmp/longjmp, dwarf 是用来处理 unwind, 就是从目前的函式回到上一个函式, 类似 bt.cpp 做的事情, dwarf 的作法需要去理解 dwarf 格式, 听说是不得了的复杂, 我不想 花时间在上头, 而 setjmp/longjmp 我已经知道其实作原理, 不需要在花额外的功夫。 另外一个需要的能力就是知道要回到那一个 function, 这就是靠神秘的 LSDA 的内容来 得知, g++ 会在 .gcc_except_table section 插入某些资讯, 让 __gxx_personality_sj0 可以用来判断要回到那个函式。 env: 32 bit debian 编译 gcc-3.4.4 tar xvf gcc-3.4.4.tar.bz2 mkdir gcc-build cd gcc-build ../gcc-3.4.4/configure --enable-languages=c,c++ --enable-sjlj-exceptions make make install 编译时可能会遇到一些 header 的问题, 我把 /usr/include/i386-linux-gnu/* link 到 /usr/include root@debian32:/usr/include# ls -l sys lrwxrwxrwx 1 root root 32 Dec 26 15:42 sys -> /usr/include/i386-linux-gnu/sys 没支援 --enable-sjlj-exceptions g++ 的编译错误 descent@debian64:eh_impl$ g++ -g -o a a.cpp /tmp/ccRq4BBp.o: In function `main': /home/descent/git/eh_impl/a.cpp:126: undefined reference to `__gxx_personality_sj0' /home/descent/git/eh_impl/a.cpp:138: undefined reference to `_Unwind_SjLj_Register' /home/descent/git/eh_impl/a.cpp:142: undefined reference to `_Unwind_SjLj_Unregister' collect2: error: ld returned 1 exit status 支援 --enable-sjlj-exceptions 的 g++ descent@debian32:eh_impl$ g++ -v Reading specs from /usr/local/lib/gcc/i686-pc-linux-gnu/3.4.4/specs Configured with: ../gcc-3.4.4/configure --enable-languages=c,c++ --enable-sjlj-exceptions Thread model: posix gcc version 3.4.4 a.cpp 是 binary hack 书上提供的范例, 提供了对照, try/catch/throw 是怎麽转成一 般的 c++ 程式码, 看上去就清楚了, 最麻烦的就是那个 lsda 到底是怎麽样的资料结 构, 可惜书上也没写得很清楚, 看来只能看第 0 手资料了。 list 1. a.cpp 执行结果 /usr/local/bin/g++ -g -o a a.cpp 使用 ldd 查看 so descent@debian32:eh_impl$ ldd a linux-gate.so.1 (0xb77bf000) libstdc++.so.6 => /usr/lib/i386-linux-gnu/libstdc++.so.6 (0xb763a000) libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb75e5000) libgcc_s.so.1 => /lib/i386-linux-gnu/libgcc_s.so.1 (0xb75c8000) # 没有 dynamic lik 我们编译的那个 libgcc_s.so.1 libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7411000) /lib/ld-linux.so.2 (0x8007d000) debian32:eh_impl$ export LD_LIBRARY_PATH=/usr/local/lib # x86 32 bit environment 再一次 ldd descent@debian32:eh_impl$ ldd a linux-gate.so.1 (0xb779e000) libstdc++.so.6 => /usr/local/lib/libstdc++.so.6 (0xb76b6000) libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb764f000) libgcc_s.so.1 => /usr/local/lib/libgcc_s.so.1 (0xb7647000) libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7490000) /lib/ld-linux.so.2 (0x800e2000) 这样就对了。 descent@debian32:eh_impl$ ./a func1 begin obj ctor func2 begin obj dtor thrown_obj: 100 list 1 的结果可以成功呼叫解构函式, 以及跑到正确的 catch 程式码。可以用 gdb 跑 跑看, exception handle 的神秘感解除了一半, 另外一半还在 libunwind, libgcc 里头 的函式。 a.cpp L166 就是 L118 ~ 120 那 3 行; a.cpp L137 ~ 145 就是 L149 ~ 167 那麽多行 。 a.cpp 1 // test c++ exception handle by g++ 3.4.4 2 // example code from binary hacks chinese version, page 145 3 4 #include <cstdio> 5 #include <iostream> 6 #include <typeinfo> 7 using namespace std; 8 9 #include <unwind.h> 10 11 extern "C" 12 { 13 // libsupc++/eh_alloc.cc 14 void * __cxa_allocate_exception(std::size_t thrown_size); 15 16 // libsupc++/eh_throw.cc 17 //void __cxa_throw (void *obj, std::type_info *tinfo, void (*dest) (void *)); 18 void __cxa_throw (void *obj, void *tinfo, void (*dest) (void *)); 19 20 // libsupc++/eh_catch.cc 21 void * __cxa_begin_catch (void *exc_obj_in); 22 void __cxa_end_catch (); 23 24 25 #define PERSONALITY_FUNCTION __gxx_personality_sj0 26 27 // libsupc++/eh_personality.cc 28 _Unwind_Reason_Code PERSONALITY_FUNCTION (int version, 29 _Unwind_Action actions, 30 _Unwind_Exception_Class exception_class, 31 struct _Unwind_Exception *ue_header, 32 struct _Unwind_Context *context); 33 34 35 } 36 37 struct Lsda 38 { 39 unsigned char start_format; 40 unsigned char type_format; 41 unsigned char type_length; 42 unsigned char call_site_format; 43 unsigned char call_site_length; 44 unsigned char call_site_table[2]; 45 signed char action_table[2]; 46 const std::type_info *catch_type[1]; 47 }__attribute__((packed)); 48 49 Lsda my_lsda= 50 { 51 0xff, 52 0x00, 53 10, 54 0x01, 55 2, 56 {0,1}, 57 {1,0}, 58 &typeid(int), 59 }; 60 61 62 // unwind-sjlj.c 63 /* This structure is allocated on the stack of the target function. 64 This must match the definition created in except.c:init_eh. */ 65 struct SjLj_Function_Context 66 { 67 /* This is the chain through all registered contexts. It is 68 filled in by _Unwind_SjLj_Register. */ 69 struct SjLj_Function_Context *prev; 70 71 /* This is assigned in by the target function before every call 72 to the index of the call site in the lsda. It is assigned by 73 the personality routine to the landing pad index. */ 74 int call_site; 75 76 /* This is how data is returned from the personality routine to 77 the target function's handler. */ 78 _Unwind_Word data[4]; 79 80 /* These are filled in once by the target function before any 81 exceptions are expected to be handled. */ 82 _Unwind_Personality_Fn personality; 83 void *lsda; 84 85 #ifdef DONT_USE_BUILTIN_SETJMP 86 /* We don't know what sort of alignment requirements the system 87 jmp_buf has. We over estimated in except.c, and now we have 88 to match that here just in case the system *didn't* have more 89 restrictive requirements. */ 90 jmp_buf jbuf __attribute__((aligned)); 91 #else 92 void *jbuf[]; 93 #endif 94 }; 95 96 //#define CXX_EH 97 98 class Obj 99 { 100 public: 101 Obj() 102 { 103 cout << "obj ctor" << endl; 104 } 105 ~Obj() 106 { 107 cout << "obj dtor" << endl; 108 } 109 110 }; 111 112 void func2() 113 { 114 cout << "func2 begin" << endl; 115 #ifdef CXX_EH 116 throw 100; 117 #else 118 void *throw_obj = __cxa_allocate_exception(sizeof(int)); 119 *(int*)throw_obj = 100; // 这就是那个 throw 100, 的那个 100 120 __cxa_throw(throw_obj, (std::type_info*)&typeid(int), NULL); 121 #endif 122 cout << "func2 end" << endl; 123 } 124 125 void func1() 126 { 127 cout << "func1 begin" << endl; 128 Obj obj; 129 130 func2(); 131 cout << "func1 end" << endl; 132 } 133 134 int main(int argc, char *argv[]) 135 { 136 #ifdef CXX_EH 137 try 138 { 139 cout << "hello" << endl; 140 func1(); 141 } 142 catch (int eh) 143 { 144 cout << "catch int: " << eh << endl; 145 } 146 147 #else 148 149 SjLj_Function_Context sjlj; 150 151 sjlj.personality = __gxx_personality_sj0; 152 sjlj.lsda = (void*)&my_lsda; 153 sjlj.call_site = 1; 154 155 if (__builtin_setjmp(sjlj.jbuf) == 1) 156 { 157 void *thrown_obj = __cxa_begin_catch((void*)sjlj.data[0]); 158 printf("thrown_obj: %d\n", *(int*)thrown_obj); 159 __cxa_end_catch(); 160 } 161 else 162 { 163 _Unwind_SjLj_Register(&sjlj); 164 //throw 100; 165 func1(); 166 } 167 _Unwind_SjLj_Unregister(&sjlj); 168 #endif 169 return 0; 170 } objdump -d a 看不到详细的反组译程式码, 我使用 gdb 来反组译, 这是意外的收获。 list 2. dis.gdb 1 >0x8048b16 <func1()+96> lea -0x28(%ebp),%eax 2 0x8048b19 <func1()+99> mov %eax,(%esp) 3 0x8048b1c <func1()+102> call 0x8048d2e <Obj::Obj()> 4 0x8048b21 <func1()+107> movl $0x1,-0x58(%ebp) 5 0x8048b28 <func1()+114> call 0x8048a32 <func2()> 6 0x8048b2d <func1()+119> movl $0x8048e5a,0x4(%esp) 7 0x8048b35 <func1()+127> movl $0x804b080,(%esp) 8 0x8048b3c <func1()+134> call 0x80487d0 <_ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc@plt> 9 0x8048b41 <func1()+139> movl $0x8048780,0x4(%esp) 10 0x8048b49 <func1()+147> mov %eax,(%esp) 11 0x8048b4c <func1()+150> call 0x8048770 <_ZNSolsEPFRSoS_E@plt> 12 0x8048b51 <func1()+155> jmp 0x8048b8c <func1()+214> 13 0x8048b53 <func1()+157> lea 0x18(%ebp),%ebp 14 0x8048b56 <func1()+160> mov -0x54(%ebp),%eax 15 0x8048b59 <func1()+163> mov %eax,-0x64(%ebp) 16 0x8048b5c <func1()+166> mov -0x64(%ebp),%edx 17 0x8048b5f <func1()+169> mov %edx,-0x60(%ebp) 18 0x8048b62 <func1()+172> lea -0x28(%ebp),%eax 19 0x8048b65 <func1()+175> mov %eax,(%esp) 20 0x8048b68 <func1()+178> movl $0x0,-0x58(%ebp) 21 0x8048b6f <func1()+185> call 0x8048d02 <Obj::~Obj()> the 1st dtor 22 0x8048b74 <func1()+190> mov -0x60(%ebp),%eax 23 0x8048b77 <func1()+193> mov %eax,-0x64(%ebp) 24 0x8048b7a <func1()+196> mov -0x64(%ebp),%edx 25 0x8048b7d <func1()+199> mov %edx,(%esp) 26 0x8048b80 <func1()+202> movl $0xffffffff,-0x58(%ebp) 27 0x8048b87 <func1()+209> call 0x80487e0 <_Unwind_SjLj_Resume@plt> 28 0x8048b8c <func1()+214> lea -0x28(%ebp),%eax 29 0x8048b8f <func1()+217> mov %eax,(%esp) 30 0x8048b92 <func1()+220> movl $0xffffffff,-0x58(%ebp) 31 0x8048b99 <func1()+227> call 0x8048d02 <Obj::~Obj()> the 2nd dtor 32 0x8048b9e <func1()+232> lea -0x5c(%ebp),%eax 33 0x8048ba1 <func1()+235> mov %eax,(%esp) 34 0x8048ba4 <func1()+238> call 0x8048810 <_Unwind_SjLj_Unregister@plt> 35 0x8048ba9 <func1()+243> add $0x6c,%esp 36 0x8048bac <func1()+246> pop %ebx 37 0x8048bad <func1()+247> pop %esi 38 0x8048bae <func1()+248> pop %edi 39 0x8048baf <func1()+249> pop %ebp 40 0x8048bb0 <func1()+250> ret list 2 L21, L31 有 2 个 dtor, 很奇怪吧, L21 是给 exception handle 用的, 当从 throw 回到 func1 时, 会莫名的抵达这里, 事实上是回到 L13 0x8048b53 这里, 然後在 执行 L27 回到上一个 stack frame (本例来说就是 main); L31 则是给正常执行流程呼 叫的 dtor, L12 有个狡猾的 jmp, 真是机关算尽。 list 3 是 g++ 3.4.4 的反组译版本, 更清楚了, 我应该早点想到的, 它不只为我解除 了 2 个 dtor 的疑惑, 还把莫名会抵达 func1() 的原因也找了出来, 甚至连那个 Lsda 也帮我厘清了, 也因为知道 Lsda 的内容, 我连带改出 g++ 5.4.0 的版本了。 list 3 是使用 try/catch/throw 的版本, list 3 L302, 303, 是不是和自己填入 a.cpp L151 ~ 153 一样呢? list 3 L303, L387 就是那个该死的 lsda, 从 list 3 L387 ~ L402, 在 .gcc_except_table section (就是 LSDA - Language Specific Data Area), 又是另外 一个狡猾的地方。 至於 g++ 5.4.0 我怎麽改出来的呢? 就是用 g++ 5.4.0 去反组译 try/catch/throw 的 版本, 把 .gcc_except_table section, 填到那个 lsda 就好了, 果然还真的不同。 再来是那个莫名回到 func1 的动作是怎麽作到的呢? 这个困扰我好久, 用 gdb 追也找不 出所以然, 照理说应该要有一个 setjmp 在这里, 才能透过 longjmp 回到这, 但我就一 直找不到哪里有 call setjmp, 直到我用 g++ -S 之後才看到, 原来 g++ 在 func1 安插 了类似 setjmp 的程式码, 这才让 _Unwind_RaiseException 有能力回到 func1。 list 3 L182 _Unwind_SjLj_Register 的动作类似 bt.cpp 那个 map<string, jmp_buf>, 把每一个 fuction 要回来的位置记起来, 它的参数 SjLj_Function_Context 里头有 jmp_buf, 得先把 jmp_buf 填好才行, 让 uw_install_context 的 longjmp 回到 这里。 由於是 g++ 插入的 code, 得从组合语言去看出来才行, 还真是难。L177 的 .L18 就是 setjmp 纪录起来的值, 这里就是在填上面说的 jmp_buf 的部份, 但并不是产生呼叫 setjmp 的程式码, 而是填入那个 jmp_buf 所需要的值就可以了, 所以 _Unwind_RaiseException 发动 uw_install_context, 就会回到 L202, 和 gdb 的显示是 一样的。 把 func1() Obj obj; 拿掉, 再看 g++ 产生的 a.s, 就会发现那个 func1 和 c 的长相 一样, 不会被偷偷插入那麽多程式码了。 #define uw_install_context(CURRENT, TARGET) \ do \ { \ _Unwind_SjLj_SetContext ((TARGET)->fc); \ longjmp ((TARGET)->fc->jbuf, 1); \ } \ while (0) list 3 L172 ~ 173 是不是有类似的行为, 塞入 __gxx_personality_sj0, lsda 这些资 料, lsda 是我目前还无法突破的部份。 list 3. g++-3.4.4 -S a.cpp a-3.3.4.s 1 .file "a.cpp" 2 .text 3 .align 2 4 .type _ZSt17__verify_groupingPKcjRKSs, @function 116 .LC0: 117 .string "func2 begin" 118 .LC1: 119 .string "func2 end" 120 .text 121 .align 2 122 .globl _Z5func2v 123 .type _Z5func2v, @function 124 _Z5func2v: 125 pushl %ebp 126 movl %esp, %ebp 127 subl $24, %esp 128 movl $.LC0, 4(%esp) 129 movl $_ZSt4cout, (%esp) 130 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 131 movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp) 132 movl %eax, (%esp) 133 call _ZNSolsEPFRSoS_E 134 movl $4, (%esp) 135 call __cxa_allocate_exception 136 movl $100, (%eax) 137 .L11: 138 movl $0, 8(%esp) 139 movl $_ZTIi, 4(%esp) 140 movl %eax, (%esp) 141 call __cxa_throw 142 movl $.LC1, 4(%esp) 143 movl $_ZSt4cout, (%esp) 144 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 145 movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp) 146 movl %eax, (%esp) 147 call _ZNSolsEPFRSoS_E 148 leave 149 ret 150 .L10: 151 .size _Z5func2v, .-_Z5func2v 152 .globl _Unwind_SjLj_Resume 153 .globl __gxx_personality_sj0 154 .globl _Unwind_SjLj_Register 155 .globl _Unwind_SjLj_Unregister 156 .section .rodata 157 .LC2: 158 .string "func1 begin" 159 .LC3: 160 .string "func1 end" 161 .text 162 .align 2 163 .globl _Z5func1v 164 .type _Z5func1v, @function 165 _Z5func1v: 166 pushl %ebp 167 movl %esp, %ebp 168 pushl %edi 169 pushl %esi 170 pushl %ebx 171 subl $108, %esp 172 movl $__gxx_personality_sj0, -68(%ebp) 173 movl $.LLSDA1420, -64(%ebp) 174 leal -60(%ebp), %eax 175 leal -24(%ebp), %edx 176 movl %edx, (%eax) 177 movl $.L18, %edx 178 movl %edx, 4(%eax) 179 movl %esp, 8(%eax) 180 leal -92(%ebp), %eax 181 movl %eax, (%esp) 182 call _Unwind_SjLj_Register 183 movl $.LC2, 4(%esp) 184 movl $_ZSt4cout, (%esp) 185 movl $-1, -88(%ebp) 186 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 187 movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp) 188 movl %eax, (%esp) 189 call _ZNSolsEPFRSoS_E 190 leal -40(%ebp), %eax 191 movl %eax, (%esp) 192 call _ZN3ObjC1Ev 193 movl $1, -88(%ebp) 194 call _Z5func2v 195 movl $.LC3, 4(%esp) 196 movl $_ZSt4cout, (%esp) 197 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 198 movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp) 199 movl %eax, (%esp) 200 call _ZNSolsEPFRSoS_E 201 jmp .L15 202 .L18: 203 leal 24(%ebp), %ebp 204 movl -84(%ebp), %eax 205 movl %eax, -100(%ebp) 206 .L14: 207 movl -100(%ebp), %edx 208 movl %edx, -96(%ebp) 209 leal -40(%ebp), %eax 210 movl %eax, (%esp) 211 movl $0, -88(%ebp) 212 call _ZN3ObjD1Ev 213 movl -96(%ebp), %eax 214 movl %eax, -100(%ebp) 215 .L16: 216 movl -100(%ebp), %edx 217 movl %edx, (%esp) 218 movl $-1, -88(%ebp) 219 call _Unwind_SjLj_Resume 220 .L15: 221 leal -40(%ebp), %eax 222 movl %eax, (%esp) 223 movl $-1, -88(%ebp) 224 call _ZN3ObjD1Ev 225 .L13: 226 leal -92(%ebp), %eax 227 movl %eax, (%esp) 228 call _Unwind_SjLj_Unregister 229 addl $108, %esp 230 popl %ebx 231 popl %esi 232 popl %edi 233 popl %ebp 234 ret 235 .size _Z5func1v, .-_Z5func1v 236 .section .gcc_except_table,"a",@progbits 237 .LLSDA1420: 238 .byte 0xff 239 .byte 0xff 240 .byte 0x1 241 .uleb128 .LLSDACSE1420-.LLSDACSB1420 242 .LLSDACSB1420: 243 .uleb128 0x0 244 .uleb128 0x0 245 .LLSDACSE1420: 246 .text 247 .section .rodata 248 .LC4: 249 .string "obj dtor\n" 250 .section .gnu.linkonce.t._ZN3ObjD1Ev,"ax",@progbits 251 .align 2 252 .weak _ZN3ObjD1Ev 253 .type _ZN3ObjD1Ev, @function 254 _ZN3ObjD1Ev: 255 pushl %ebp 256 movl %esp, %ebp 257 subl $8, %esp 258 movl $.LC4, (%esp) 259 call printf 260 leave 261 ret 262 .size _ZN3ObjD1Ev, .-_ZN3ObjD1Ev 263 .section .rodata 264 .LC5: 265 .string "obj ctor\n" 266 .section .gnu.linkonce.t._ZN3ObjC1Ev,"ax",@progbits 267 .align 2 268 .weak _ZN3ObjC1Ev 269 .type _ZN3ObjC1Ev, @function 270 _ZN3ObjC1Ev: 271 pushl %ebp 272 movl %esp, %ebp 273 subl $8, %esp 274 movl $.LC5, (%esp) 275 call printf 276 leave 277 ret 278 .size _ZN3ObjC1Ev, .-_ZN3ObjC1Ev 279 .section .rodata 280 .LC6: 281 .string "hello" 282 .LC7: 283 .string "catch int: " 284 .text 285 .align 2 286 .globl main 287 .type main, @function 288 main: 289 pushl %ebp 290 movl %esp, %ebp 291 pushl %edi 292 pushl %esi 293 pushl %ebx 294 subl $92, %esp 295 andl $-16, %esp 296 movl $0, %eax 297 addl $15, %eax 298 addl $15, %eax 299 shrl $4, %eax 300 sall $4, %eax 301 subl %eax, %esp 302 movl $__gxx_personality_sj0, -44(%ebp) 303 movl $.LLSDA1421, -40(%ebp) 304 leal -36(%ebp), %eax 305 leal -12(%ebp), %edx 306 movl %edx, (%eax) 307 movl $.L31, %edx 308 movl %edx, 4(%eax) 309 movl %esp, 8(%eax) 310 leal -68(%ebp), %eax 311 movl %eax, (%esp) 312 call _Unwind_SjLj_Register 313 movl $.LC6, 4(%esp) 314 movl $_ZSt4cout, (%esp) 315 movl $2, -64(%ebp) 316 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 317 movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp) 318 movl %eax, (%esp) 319 call _ZNSolsEPFRSoS_E 320 call _Z5func1v 321 jmp .L24 322 .L30: 323 cmpl $1, -84(%ebp) 324 je .L25 325 movl -76(%ebp), %eax 326 movl %eax, (%esp) 327 movl $-1, -64(%ebp) 328 call _Unwind_SjLj_Resume 329 .L25: 330 movl -76(%ebp), %edx 331 movl %edx, (%esp) 332 movl $-1, -64(%ebp) 333 call __cxa_begin_catch 334 movl (%eax), %eax 335 movl %eax, -16(%ebp) 336 movl $.LC7, 4(%esp) 337 movl $_ZSt4cout, (%esp) 338 movl $1, -64(%ebp) 339 call _ZStlsISt11char_traitsIcEERSt13basic_ostreamIcT_ES5_PKc 340 movl %eax, %edx 341 movl -16(%ebp), %eax 342 movl %eax, 4(%esp) 343 movl %edx, (%esp) 344 call _ZNSolsEi 345 movl $_ZSt4endlIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_, 4(%esp) 346 movl %eax, (%esp) 347 call _ZNSolsEPFRSoS_E 348 jmp .L27 349 .L31: 350 leal 12(%ebp), %ebp 351 movl -64(%ebp), %eax 352 movl -60(%ebp), %edx 353 movl %edx, -76(%ebp) 354 movl -56(%ebp), %edx 355 movl %edx, -84(%ebp) 356 cmpl $1, %eax 357 je .L30 358 .L26: 359 movl -76(%ebp), %eax 360 movl %eax, -80(%ebp) 361 call __cxa_end_catch 362 movl -80(%ebp), %edx 363 movl %edx, -76(%ebp) 364 .L28: 365 movl -76(%ebp), %eax 366 movl %eax, (%esp) 367 movl $-1, -64(%ebp) 368 call _Unwind_SjLj_Resume 369 .L27: 370 call __cxa_end_catch 371 .L24: 372 movl $0, -72(%ebp) 373 .L23: 374 leal -68(%ebp), %eax 375 movl %eax, (%esp) 376 call _Unwind_SjLj_Unregister 377 movl -72(%ebp), %eax 378 leal -12(%ebp), %esp 379 popl %ebx 380 popl %esi 381 popl %edi 382 popl %ebp 383 ret 384 .size main, .-main 385 .section .gcc_except_table 386 .align 4 387 .LLSDA1421: 388 .byte 0xff 389 .byte 0x0 390 .uleb128 .LLSDATT1421-.LLSDATTD1421 391 .LLSDATTD1421: 392 .byte 0x1 393 .uleb128 .LLSDACSE1421-.LLSDACSB1421 394 .LLSDACSB1421: 395 .uleb128 0x0 396 .uleb128 0x0 397 .uleb128 0x1 398 .uleb128 0x1 399 .LLSDACSE1421: 400 .byte 0x1 401 .byte 0x0 402 .align 4 403 .long _ZTIi 404 .LLSDATT1421: 405 .text 406 .section .gnu.linkonce.t._ZSt3minIjERKT_S2_S2_,"ax",@progbits 407 .align 2 408 .weak _ZSt3minIjERKT_S2_S2_ 409 .type _ZSt3minIjERKT_S2_S2_, @function 430 .text 431 .align 2 454 .align 2 455 .type _GLOBAL__I_my_lsda, @function 456 _GLOBAL__I_my_lsda: 457 pushl %ebp 458 movl %esp, %ebp 459 subl $8, %esp 460 movl $65535, 4(%esp) 461 movl $1, (%esp) 462 call _Z41__static_initialization_and_destruction_0ii 463 leave 464 ret 465 .size _GLOBAL__I_my_lsda, .-_GLOBAL__I_my_lsda 466 .section .ctors,"aw",@progbits 467 .align 4 468 .long _GLOBAL__I_my_lsda 469 .text 470 .align 2 471 .type _GLOBAL__D_my_lsda, @function 472 _GLOBAL__D_my_lsda: 473 pushl %ebp 474 movl %esp, %ebp 475 subl $8, %esp 476 movl $65535, 4(%esp) 477 movl $0, (%esp) 478 call _Z41__static_initialization_and_destruction_0ii 479 leave 480 ret 481 .size _GLOBAL__D_my_lsda, .-_GLOBAL__D_my_lsda 482 .section .dtors,"aw",@progbits 483 .align 4 484 .long _GLOBAL__D_my_lsda 494 .section .note.GNU-stack,"",@progbits 495 .ident "GCC: (GNU) 3.4.4" 由於用到 typeinfo 来判断型别, 这是为什麽 exception handle 需要有 rtti 支援的原 因。 从 global object, static object, virtaul function, rtti 到 exception handle, 现在你知道 c++ 有那麽多的黑魔法, c++ 真是不简单, 这也是为人所诟病的一个特性, 太黑箱了。 在 c++ 这麽多的特性, 我最有兴趣的是 virtual function 和 exception handle 的实 作, 我已经找了多年的资料, 有点收获真是开心。 typeid ref: typeid详解 ( https://goo.gl/i8t0TU ) 执行时期型态资讯(RTTI) ( https://goo.gl/SdoIX6 ) ref: C++ exception handling internals ( https://goo.gl/4zQhql ) (感谢帅叔叔提供) http://www.hexblog.com/wp-content/uploads/2012/06/Recon-2012-Skochinsky-Compiler-Internals.pdf ( https://goo.gl/N70Kzk ) c++ 异常处理(1) ( https://goo.gl/orGGA5 ) c++ 异常处理(2) ( https://goo.gl/MSwKzu ) Exception Handling in LLVM ( https://goo.gl/gauszo ) Itanium C++ ABI: Exception Handling ($Revision: 1.1 $) ( https://goo.gl/7x2i3H ) 非本地跳转:应用 ( https://goo.gl/OGa4vu ) 浅谈C++例外处理 (中篇) ( https://goo.gl/2Qg8Ta ) Chapter 8. Exception Frames ( https://goo.gl/jivOjq ) GCC C++ Exception Handling Implementation ( https://goo.gl/D1xGfL ) .gcc_except_table ( https://goo.gl/0BYPhM ) Elf-Section .gcc_except_table ( https://goo.gl/mpyUFD ) SJLJ EH: C++ exception handling in PNaCl using setjmp()+longjmp() ( https://goo.gl/G2RYZd ) binary hacks 繁体中文版 item 38, 39, 40, 41 // 本文使用 Blog2BBS 自动将Blog文章转成缩址的BBS纯文字 http://goo.gl/TZ4E17 // blog 版本 http://descent-incoming.blogspot.tw/2016/12/c-exception-handling1.html -- 纸上得来终觉浅,绝知此事要躬行。 --



※ 发信站: 批踢踢实业坊(ptt.cc), 来自: 49.218.4.162
※ 文章网址: https://webptt.com/cn.aspx?n=bbs/C_and_CPP/M.1484315788.A.52E.html
1F:推 bachelorwhc: 太强惹 01/13 22:07
2F:推 Caesar08: 推 01/13 22:45
3F:推 ilikekotomi: 虽然看不懂还是要推 01/13 23:16
4F:推 lc85301: 这个必须推 01/13 23:17
5F:推 b98901056: 先推再来努力研究@@ 01/13 23:31
6F:推 genius945: 推 原来是这样啊(咦? 01/14 00:08
7F:推 ko27tye: 天哪 改天再看好惹 01/14 02:00
8F:推 Neisseria: d 大的东西常常看不懂,还是推一个 01/14 08:18
板上很多文章我也看不懂的。
9F:推 Ebergies: 很好奇怎麽会想要去解析实际做法呢? 纯粹好奇而已吗~ 01/14 17:28
只是单纯「想知道」而已, 我不是作 compiler 相关的工作, 不过搞这个还真吃力不讨好, 我应该多学点民间专长才是。 ※ 编辑: descent (101.15.66.217), 01/14/2017 21:09:32
10F:推 sunneo: uefi上要是这个也弄起来该有多好 02/13 00:23







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:BuyTogether站内搜寻

TOP