2013-08-19 68 views
4

我想讀的Linux源代碼(2.6.11)爲什麼linux下的異常處理程序

在異常處理程序,在entry.S中, ERROR_CODE的序幕設定的數據段__USER_DS:

movl $(__USER_DS), %ecx 
movl %ecx, %ds 
movl %ecx, %es 

我不知道爲什麼在這裏加載用戶數據段。由於它應該輸入在內核模式下運行的異常處理程序代碼,所以選擇器應該是__KERNEL_DS。

我查了其他版本的代碼,他們在這個地方也做了同樣的事情。

回答

3

如果輸入的異常處理程序與dses已經設置爲數據段,除了可能延遲一微秒之外,沒有什麼區別。異常處理程序通常不需要很快。

但是,可能會導致異常處理程序?難道這是因爲一個壞的值被加載到一個段寄存器然後被引用?在這種情況下,代碼建立安全環境非常重要。 cs由異常調用設置。爲了防彈,ssesp也應該建立。


跟帖:

縱觀2-6.22.18內核i386的,我沒有看到正是:

error_code: /* the function address is in %fs's slot on the stack */ 
    pushl %es 
    ... pushes %ds, %eax, %ebp, %edi, %esi, %edx, %ecx, %ebx, %fs 
    ... along with pseudo-ops to manage stack frame layout 
    movl $(__KERNEL_PERCPU), %ecx 
    movl %ecx, %fs 
    popl %ecx // retrieves saved %fs 
    ... sets up registers for the exception function 

符號__KERNEL_PERCPU是定義一個宏(在include/asm-i386/segment.h )爲非SMP機器的0,SMP爲(GDT_ENTRY_PERCPU * 8)。 8用於GDT入口大小(我認爲),GDT_ENTRY_PERCPU與每個CPU GDT中的入口相關。它的值是<base> + 15,其中註釋表示爲「默認用戶DS」,所以它實際上是相同的東西。

內核數據段通過fsss訪問。很多內核數據訪問都在堆棧中。通過保持通過ds訪問的用戶模式描述符,需要非常少量的段寄存器加載。

+0

對不起,我的問題太含糊。我的意思是爲什麼它加載__USER_DS而不是__KERNEL_DS。我修改了原來的問題。 – Holmes

+0

@霍爾姆斯:我已經修改了我的答案。這是否解釋得更好? – wallyk

+0

是的。 thx爲您的詳細答案。 – Holmes

0

在entry.S中:

#define RESTORE_ALL 
    RESTORE_REGS 
    addl $4, %esp; 
1: iret; 
.section .fixup,"ax"; 
2: sti; 
    movl $(__USER_DS), %edx; 
    movl %edx, %ds; 
    movl %edx, %es; 
    movl $11,%eax; 
    call do_exit; 
.previous; 
.section __ex_table,"a"; 
    .align 4; 
    .long 1b,2b; 
.previous 

這個宏將異常/中斷/系統調用結束時調用。修正碼ds & es設置爲USER_DS,表明一旦ds的DPL不是3(用戶權限),iret本身就會引發異常。

因此,在異常/中斷/系統調用的最開始,linux將ds & es設置爲USER_DS以避免此異常。