为什么linux在异常处理程序的开头将数据段设置为uu USER_DS

为什么linux在异常处理程序的开头将数据段设置为uu USER_DS,linux,data-segment,exceptionhandler,Linux,Data Segment,Exceptionhandler,我正在尝试阅读Linux源代码(2.6.11) 在异常处理程序的entry.s处, 错误代码: movl $(__USER_DS), %ecx movl %ecx, %ds movl %ecx, %es 我不知道为什么在这里加载用户数据段。因为它应该输入在内核模式下运行的异常处理程序代码,所以选择器应该是uu kernel_DS 我检查了其他版本的代码,它们在这里也做了同样的事情。如果异常处理程序是在ds和es已设置为数据段的情况下输入的,则除了可能有微秒的延迟外,没有任何区别。异常处理程序通

我正在尝试阅读Linux源代码(2.6.11)

在异常处理程序的entry.s处, 错误代码:

movl $(__USER_DS), %ecx
movl %ecx, %ds
movl %ecx, %es
我不知道为什么在这里加载用户数据段。因为它应该输入在内核模式下运行的异常处理程序代码,所以选择器应该是uu kernel_DS


我检查了其他版本的代码,它们在这里也做了同样的事情。

如果异常处理程序是在
ds
es
已设置为数据段的情况下输入的,则除了可能有微秒的延迟外,没有任何区别。异常处理程序通常不需要很快

但是,什么可能会导致转到异常处理程序?这可能是因为一个坏值被加载到段寄存器中,然后被引用?在这种情况下,准则必须建立一个安全的环境<代码>cs由异常调用设置。为了防弹,还应设置
ss
esp


后续行动:

查看i386的2-6.22.18内核,我看不出确切的情况:

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
符号
\uuuu KERNEL\u perpu
是一个宏定义(在
include/asm-i386/segment.h
中),对于非SMP机器定义为
0
,对于SMP机器定义为
(GDT\u ENTRY\u perpu*8)
。8表示GDT条目大小(我认为),而
GDT\u entry\u perpu
与每CPU GDT中的条目相关。它的值是
+15
,注释表明它是“默认用户DS”,因此事实上,它是相同的

内核数据段通过
fs
ss
访问。许多内核数据访问都在堆栈上。通过保持通过ds访问用户模式描述符,只需加载很少的段寄存器。

在条目中。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&es的DPL不是3(用户权限),iret本身将引发异常


因此,linux在异常/中断/系统调用的最开始将ds&es设置为USER_ds以避免此异常。

对不起,我的问题太模糊了。我的意思是为什么它加载的是u用户而不是u内核。我已经修改了原来的问题。@Holmes:我已经修改了我的答案。这能更好地解释它吗?@walllyk:我想我终于弄清楚了“…很少加载段寄存器”意味着什么。又来了!请您解释一下“内核数据段是通过fs和ss访问的”。这是否意味着内核异常不能使用DS?@dimba:异常可以使用DS:入口代码设置它。然而,DS被映射到用户空间,可能是为了检查/更改用户模式堆栈和变量。