簡體   English   中英

function 何時會在 c++ 中包含堆棧 _Unwind_Resume 調用?

[英]when does a function will include stack _Unwind_Resume call in c++?

我現在正在研究 c++ 異常,遇到了麻煩,程序顯示如下

#include<iostream>
#include<unistd.h>
#include<string>
#include<thread>
#include<vector>
#include<exception>
using namespace std;


vector<int> vec(20);


void fn()throw() {
        vec.at(10);
}

int main(){
        fn();

return 0;
}

我使用 gdb 來反匯編fn() ,我們可以看到callq 0x4008d0 _Unwind_Resume@plt ,這是對堆棧展開操作的調用,因為 vector::at 可能會拋出超出范圍的異常

Dump of assembler code for function fn():
   0x00000000004009e6 <+0>:     push   %rbp
   0x00000000004009e7 <+1>:     mov    %rsp,%rbp
   0x00000000004009ea <+4>:     mov    $0xa,%esi
   0x00000000004009ef <+9>:     mov    $0x6020a0,%edi
   0x00000000004009f4 <+14>:    callq  0x400ba6 <std::vector<int, std::allocator<int> >::at(unsigned long)>
   0x00000000004009f9 <+19>:    jmp    0x400a11 <fn()+43>
   0x00000000004009fb <+21>:    cmp    $0xffffffffffffffff,%rdx
   0x00000000004009ff <+25>:    je     0x400a09 <fn()+35>
   0x0000000000400a01 <+27>:    mov    %rax,%rdi
   0x0000000000400a04 <+30>:    callq  0x4008d0 <_Unwind_Resume@plt>
   0x0000000000400a09 <+35>:    mov    %rax,%rdi
   0x0000000000400a0c <+38>:    callq  0x400880 <__cxa_call_unexpected@plt>
   0x0000000000400a11 <+43>:    pop    %rbp
   0x0000000000400a12 <+44>:    retq   
End of assembler dump.

但是,當我嘗試通過調用 function 來模仿這個進度時,會拋出異常,匯編代碼調用 <_Unwind_Resume>不存在,為什么?

#include<iostream>
#include<unistd.h>
#include<string>
#include<thread>
#include<vector>
#include<exception>
using namespace std;


class myException:public exception  
{  
        public:  
                myException(){ } 
};


void fn()throw() {
        throw myException();
}

void fn2()throw(){
        fn();
}


int main(){
        fn2();

        return 0;
}


function fn2() 的匯編代碼,它不包括調用 Unwind_Resume@plt ,為什么?

(gdb) disassemble fn2
Dump of assembler code for function fn2():
   0x0000000000400aec <+0>:     push   %rbp
   0x0000000000400aed <+1>:     mov    %rsp,%rbp
   0x0000000000400af0 <+4>:     callq  0x400aa6 <fn()>
   0x0000000000400af5 <+9>:     nop
   0x0000000000400af6 <+10>:    pop    %rbp
   0x0000000000400af7 <+11>:    retq   
End of assembler dump.

由於fn2僅調用聲明為throw()fn ,因此沒有異常可以傳播到fn的活動堆棧幀。 GCC 認識到這種情況並優化異常處理程序。

在原始情況下,這是不可能的,因為std::vector::at(size_type)可以拋出。 僅由於throw()聲明才需要異常處理程序,以便在發生異常時調用std::unexpected()

_Unwind_Resume僅在堆棧幀在展開時需要一些特殊操作時才會顯示(例如調用析構函數或std::unexpected() )。 否則,Itanium C++ ABI(由 GCC 使用)根本不需要任何每幀操作,這就是為什么這種實現有時被稱為零成本異常處理的原因。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM