我想讀的Linux源代碼(2.6.11)爲什麼linux下的異常處理程序
在異常處理程序,在entry.S中, ERROR_CODE的序幕設定的數據段__USER_DS:
movl $(__USER_DS), %ecx
movl %ecx, %ds
movl %ecx, %es
我不知道爲什麼在這裏加載用戶數據段。由於它應該輸入在內核模式下運行的異常處理程序代碼,所以選擇器應該是__KERNEL_DS。
我查了其他版本的代碼,他們在這個地方也做了同樣的事情。
我想讀的Linux源代碼(2.6.11)爲什麼linux下的異常處理程序
在異常處理程序,在entry.S中, ERROR_CODE的序幕設定的數據段__USER_DS:
movl $(__USER_DS), %ecx
movl %ecx, %ds
movl %ecx, %es
我不知道爲什麼在這裏加載用戶數據段。由於它應該輸入在內核模式下運行的異常處理程序代碼,所以選擇器應該是__KERNEL_DS。
我查了其他版本的代碼,他們在這個地方也做了同樣的事情。
如果輸入的異常處理程序與ds
和es
已經設置爲數據段,除了可能延遲一微秒之外,沒有什麼區別。異常處理程序通常不需要很快。
但是,可能會導致異常處理程序?難道這是因爲一個壞的值被加載到一個段寄存器然後被引用?在這種情況下,代碼建立安全環境非常重要。 cs
由異常調用設置。爲了防彈,ss
和esp
也應該建立。
跟帖:
縱觀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」,所以它實際上是相同的東西。
內核數據段通過fs
和ss
訪問。很多內核數據訪問都在堆棧中。通過保持通過ds
訪問的用戶模式描述符,需要非常少量的段寄存器加載。
在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以避免此異常。
對不起,我的問題太含糊。我的意思是爲什麼它加載__USER_DS而不是__KERNEL_DS。我修改了原來的問題。 – Holmes
@霍爾姆斯:我已經修改了我的答案。這是否解釋得更好? – wallyk
是的。 thx爲您的詳細答案。 – Holmes