Linux kernel 为什么有两个重叠的数据段(例如在Linux内核中)?

Linux kernel 为什么有两个重叠的数据段(例如在Linux内核中)?,linux-kernel,x86,operating-system,kernel,memory-segmentation,Linux Kernel,X86,Operating System,Kernel,Memory Segmentation,在Linux内核以及许多x86在线教程中,我看到人们建议使用两个代码段和两个数据段。我理解需要两个代码段,因为CPL需要与DPL完全匹配(对于不一致的代码段) 但是,这些教程(也没有关于StackOverflow的任何相关问题)都没有明确说明为什么我们需要两个数据段。这些工作方式与代码段不同,因为CPL=0的进程可以访问DPL=3的数据段 拥有两个数据段的缺点是,如果在不同权限级别的进程之间进行切换,则必须重新加载DS、ES等寄存器 所以我的具体问题是:考虑到我们使用的是平面内存模型,所以所有代

在Linux内核以及许多x86在线教程中,我看到人们建议使用两个代码段和两个数据段。我理解需要两个代码段,因为CPL需要与DPL完全匹配(对于不一致的代码段)

但是,这些教程(也没有关于StackOverflow的任何相关问题)都没有明确说明为什么我们需要两个数据段。这些工作方式与代码段不同,因为CPL=0的进程可以访问DPL=3的数据段

拥有两个数据段的缺点是,如果在不同权限级别的进程之间进行切换,则必须重新加载DS、ES等寄存器

所以我的具体问题是:考虑到我们使用的是平面内存模型,所以所有代码和段都完全重叠,那么有一个用户和一个内核数据段,而不是只有一个用户数据段,它有什么用途呢?

有一个解释

引用英特尔手册(第5.7节)

使用堆栈段的段选择器加载SS寄存器时,也会进行特权级别检查。
此处,与堆栈段相关的所有特权级别必须与CPL匹配;也就是说,堆栈段选择器的CPL、RPL和堆栈段描述符的DPL必须相同。如果RPL和DPL不相等 对于CPL,将生成一般保护异常(#GP)

重点矿山

也就是说,
SS
从内核加载时(或在切换期间)需要DPL等于0的数据段。
这适用于32位模式

在64位模式下,要抑制任何运行时检查(包括上一个),请执行以下操作1

在64位模式下,处理器不会对空段选择器执行运行时检查。处理器可以 当试图访问被引用段寄存器有错误的内存时,不会导致#GP故障 空段选择器

出于完整性考虑,在执行堆栈操作时,所有相关信息(地址大小、操作数大小和堆栈地址大小)要么从代码段恢复,要么隐式设置为64位


1如果我没记错的话,出于兼容性原因,64位模式仍然使用内核数据段