为何list<Foo>相关代码会生成含看似不可达unwind处理的汇编?
为什么GCC和Clang生成的汇编里会有看似不可达的 unwind 代码块?
先看你给出的C++代码:
list<Foo> fooList; processList(&fooList);
GCC 6.2(无优化)生成的汇编:
lea rax, [rbp-48] mov rdi, rax call processList(std::__cxx11::list<Foo, std::allocator<Foo>>*) lea rax, [rbp-48] mov rdi, rax call std::__cxx11::list<Foo, std::allocator<Foo>>::~list() jmp .L11 mov rbx, rax lea rax, [rbp-48] mov rdi, rax call std::__cxx11::list<Foo, std::allocator<Foo>>::~list() mov rax, rbx mov rdi, rax call _Unwind_Resume .L11: add rsp, 40 pop rbx pop rbp ret
Clang 5.0.0生成的汇编:
call processList(std::__cxx11::list<Foo, std::allocator<Foo>>*) jmp .LBB5_1 .LBB5_1: lea rdi, [rbp - 24] call std::__cxx11::list<Foo, std::allocator<Foo>>::~list() add rsp, 48 pop rbp ret lea rdi, [rbp - 24] mov ecx, edx mov qword ptr [rbp - 32], rax mov dword ptr [rbp - 36], ecx call std::__cxx11::list<Foo, std::allocator<Foo>>::~list() mov rdi, qword ptr [rbp - 32] call _Unwind_Resume
原因解释:
这些看似“不可达”的代码块,其实是编译器为异常处理的 unwind 流程生成的逻辑,核心是保证C++的RAII语义——不管函数是正常返回,还是中途抛出异常,局部对象fooList都必须被正确析构。
- 正常执行路径下,调用完
processList后,会执行一次析构,然后通过jmp指令跳到最后的清理返回块(.L11或.LBB5_1),这时候那些在jmp之后的代码确实不会被走到。 - 但如果
processList抛出了异常,程序的控制流会直接交给C++的异常处理框架(比如_Unwind_Resume),这时候框架会通过**异常处理表(EH Table)**找到专门的 unwind 代码块,也就是你看到的那些“不可达”的部分,执行fooList的析构,然后继续向上传播异常。 - 这些代码块不在正常的控制流里,但它们是异常处理机制的关键部分,编译器必须生成它们来确保局部对象不会因为异常泄露,这是C++异常安全的基础要求。
内容的提问来源于stack exchange,提问作者Paul Floyd
相关产品推荐
相关产品推荐

