2013-05-27 31 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上,它看起来仍然是必需的。 –