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