Bra*_*ing 2 x86 operating-system kernel linux-kernel memory-segmentation
在Linux内核以及在线的许多x86教程中,我看到人们建议使用两个代码段和两个数据段.我理解需要两个代码段,因为CPL需要与DPL完全匹配(对于不符合的段).
但是,这些教程中没有一个(也没有任何关于StackOverflow的相关问题),具体说明为什么我们需要两个数据段.这些工作与代码段不同,因为CPL = 0的进程可以访问DPL = 3的数据段.
如果我们在不同权限级别的进程之间切换,则具有两个数据段的缺点是必须重新加载DS,ES等寄存器.
所以我的具体问题是:鉴于我们使用的是平面内存模型,所有代码和段完全重叠,它的用途和内核数据段的用途是什么,而不仅仅是一个用户数据段?
有一种解释这里.
引自英特尔手册(第5.7节)
当SS寄存器加载了堆栈段的段选择器时,也会发生权限级别检查.
这里与堆栈段相关的所有权限级别必须与CPL匹配 ; 也就是说,CPL,stacksegment选择器的RPL和堆栈段描述符的DPL必须相同.如果RPL和DPL不等于CPL,则生成一般保护异常(#GP).
强调我的
也就是说,当从内核(或在交换期间)加载时,SS需要DPL等于0 的数据段.
这适用于32位模式.
在64位模式下,可以使用NULL选择器来抑制任何运行时检查(包括前一个)1
在64位模式下,处理器不会对NULL段选择器执行运行时检查.当尝试访问引用的段寄存器具有NULL段选择器的存储器时,处理器不会导致#GP错误.
出于完整性,当执行堆栈操作时,所有相关信息,地址大小,操作数大小和堆栈地址大小要么从代码段恢复,要么隐式设置为64位.
1如果我没记错的话,出于兼容性原因,64位模式仍然使用内核数据段.