我不是這方面的專家,但我會盡我所能來回答。
啓動與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;
}
0x80000000UL
和0x8000000000000000UL
分別是在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_SEGV
和INIT_FPE
初始化兩個信號處理程序時使用。
我認爲,約涵蓋了所有的問題,但如果有任何不明確或者你要我在某一特定領域拓展,讓我知道了意見。
非常感謝您的回答。我有一個跟進的問題: 根據此頁「http://man7.org/linux/man-pages/man2/sigaction.2.html」的sa_restorer已過時,不應使用。你碰巧知道還有什麼可以用在它的位置?或者該功能已被完全刪除?或者,主要的區別在於結構'k_sa_sigaction'的類型,即內核sigaction。 我的最後一個問題 - 是基於一些基本的彙編知識這個文件,或者我應該讀了先進的操作系統的編程一點? – NindzAI
您應該能夠通過閱讀[Intel指令集參考](http://www.intel.com/content/www/us/en/processors/architectures-software-developer-manuals.html) )。信號處理更復雜。我沒有做太多的Unix編程,所以這有點超出我的聯盟,但我認爲你需要看看內核源代碼,以真正理解發生了什麼 - 它從一個架構到另一個架構都有所不同。在某些平臺上放置sa_restorer看起來很安全,但例如在x86-64上,它看起來仍然是必需的。 –