2013-05-27 66 views
1

我正在研究C++中的異常處理程序。它將用於最大可靠性的消息傳遞協議中 - 即使流程捕獲到段錯誤,我也希望從收到消息的進程中隨時獲得答案。我知道C++不會引發空指針解引用或零除的異常,而是用C編寫的Java。這讓我思考並環顧四周。最後,我發現這個小程序:需要說明彙編程序和Linux信號處理的用法

https://code.google.com/p/segvcatch/source/browse/trunk/lib/

我的問題是在問候文件x86_64的-signal.h中。我不完全瞭解HANDLE_DIVIDE_OVERFLOW的細節。 REX字節?那是什麼? RESTORE2是做什麼的?什麼是_Jv_catch_segv和_Jv_catch_fpe?我理解* 的基本含義,捕獲 *,但他們在哪裏定義?

理想情況下,如果有人可以通過文件自上而下,並解決將是偉大的關鍵點。謝謝。

回答

2

我不是這方面的專家,但我會盡我所能來回答。

啓動與REX字節測試:

if ((_rip[0] & 0xf0) == 0x40) /* REX byte present. */    
    {                 
    unsigned char _rex = _rip[0] & 0x0f;        
    _is_64_bit = (_rex & 0x08) != 0;         
    _rip++;               
    }       

的REX字節是在64位模式下使用的一個指令前綴。如果指令的第一個字節的高4位匹配0x40,那麼你知道你有一個REX前綴字節。如果位3(W字段)設置爲1,則表示操作數大小爲64位。 _rip++只是跳過了前綴。

if (_rip[0] == 0xf7)             

F7告訴我們這是一種整數除法指令。

{                 
    bool _min_value_dividend = false;         
    unsigned char _modrm = _rip[1];         

的下一個字節是MODR/M字節通常給出了操作數的細節,但在這種情況下也決定除法指令的類型。所述MODR/M字節的

if (((_modrm >> 3) & 7) == 7)         

的REG字段(位3至5),通常表示一寄存器,但在這裏它的指令的操作碼的擴展。如果是7,這意味着這是一個有簽名的部門。

 {                
     if (_is_64_bit)            
      _min_value_dividend =          
      _gregs[REG_RAX] == (greg_t)0x8000000000000000UL;   
     else               
      _min_value_dividend =          
      (_gregs[REG_RAX] & 0xffffffff) == (greg_t)0x80000000UL; 
     }             

0x80000000UL0x8000000000000000UL分別是在32位和64位的最小可能負數。如果eax寄存器(股息)與該值匹配,這意味着您有最低的可能股息。

if (_min_value_dividend)           
     {                
     unsigned char _rm = _modrm & 7;        
     _gregs[REG_RDX] = 0; /* the remainder is zero */    

如果你有儘可能小的紅利,這組其餘(EDX)爲零,並且留下股息EAX作爲結果。

 switch (_modrm >> 6)           
      {               
      case 0: /* register indirect */        
      if (_rm == 5) /* 32-bit displacement */     
       _rip += 4;            
      if (_rm == 4) /* A SIB byte follows the ModR/M byte */ 
       _rip += 1;            
      break;              
      case 1: /* register indirect + 8-bit displacement */  
      _rip += 1;             
      if (_rm == 4) /* A SIB byte follows the ModR/M byte */ 
       _rip += 1;            
      break;              
      case 2: /* register indirect + 32-bit displacement */  
      _rip += 4;             
      if (_rm == 4) /* A SIB byte follows the ModR/M byte */ 
       _rip += 1;            
      break;              
      case 3:              
      break;              
      }               
     _rip += 2;              
     _gregs[REG_RIP] = (greg_t)_rip;        
     return;              
     }                

的代碼的其餘部分僅僅是檢查MODR/M字節,以確定由操作數除數所使用的字節數,因此可以提前指令指針指向下一指令。

基本上這是做它完全是在評論中所說的。如果股息是最大可能幅度的負整數,則結果等於股息,並且不會發生異常。

至於_Jv_catch_segv_Jv_catch_segv,那些在segvpatch.cpp中定義。

SIGNAL_HANDLER(catch_segv) 
{ 
    unblock_signal(SIGSEGV); 
    MAKE_THROW_FRAME(nullp); 
    handle_segv(); 
} 

SIGNAL_HANDLER(catch_fpe) 
{ 
    unblock_signal(SIGFPE); 
#ifdef HANDLE_DIVIDE_OVERFLOW 
    HANDLE_DIVIDE_OVERFLOW; 
#else 
    MAKE_THROW_FRAME(arithexception); 
#endif 
    handle_fpe(); 
} 

SIGNAL_HANDLER宏在x86_64的-signal.h中定義,並擴展到這樣的事情:

static void _Jv_catch_segv (int, siginfo_t *, void *_p __attribute__ ((__unused__))) 

最後,RESTORE2宏,它基本上由RESTORE (restore_rt, __NR_rt_sigreturn)叫,擴展爲:

asm            
    (            
    ".text\n"          
    ".byte 0 # Yes, this really is necessary\n" 
    ".align 16\n"         
    "__restore_rt:\n"        
    " movq $__NR_rt_sigreturn, %rax\n"    
    " syscall\n"        
    ); 

這將創建用於從一個信號處理程序返回一個sigreturn系統調用。這變成了功能restore_rt與此行:

void restore_rt (void) asm ("__restore_rt") 

被設置爲在該代碼中的恢復函數指針:

act.k_sa_restorer = restore_rt; 

其在INIT_SEGVINIT_FPE初始化兩個信號處理程序時使用。

我認爲,約涵蓋了所有的問題,但如果有任何不明確或者你要我在某一特定領域拓展,讓我知道了意見。

+0

非常感謝您的回答。我有一個跟進的問題: 根據此頁「http://man7.org/linux/man-pages/man2/sigaction.2.html」的sa_restorer已過時,不應使用。你碰巧知道還有什麼可以用在它的位置?或者該功能已被完全刪除?或者,主要的區別在於結構'k_sa_sigaction'的類型,即內核sigaction。 我的最後一個問題 - 是基於一些基本的彙編知識這個文件,或者我應該讀了先進的操作系統的編程一點? – NindzAI

+0

您應該能夠通過閱讀[Intel指令集參考](http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html) )。信號處理更復雜。我沒有做太多的Unix編程,所以這有點超出我的聯盟,但我認爲你需要看看內核源代碼,以真正理解發生了什麼 - 它從一個架構到另一個架構都有所不同。在某些平臺上放置sa_restorer看起來很安全,但例如在x86-64上,它看起來仍然是必需的。 –