为什么linux在异常处理程序的开头将数据段设置为uu USER_DS
我正在尝试阅读Linux源代码(2.6.11) 在异常处理程序的entry.s处, 错误代码:为什么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已设置为数据段的情况下输入的,则除了可能有微秒的延迟外,没有任何区别。异常处理程序通
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被映射到用户空间,可能是为了检查/更改用户模式堆栈和变量。