从理解Linux内核开始
80x86微处理器中包含了分段,以鼓励程序员将应用程序拆分为逻辑相关的实体,例如子程序或全局和本地数据区域。然而,以非常有限的方式使用分段。实际上,分段和分页有些多余,因为两者都可以用于分离进程的物理地址空间:分段可以为每个进程分配不同的线性地址空间,而分页可以将相同的线性地址空间映射到不同的物理地址空间。Linux更喜欢分页而不是分段,原因如下:
2.6版本的Linux只在80x86体系结构需要时才使用分段。
x86-64体系结构在长模式(64位模式)中不使用分段.由于x86有段,所以不可能不使用它们。四个段寄存器: CS、SS、DS和ES强制为0,限制为2^64。如果是这样,则提出两个问题:
发布于 2022-02-13 19:54:14
堆栈数据(堆栈段)和堆数据(数据段)混合在一起,然后从堆栈中弹出并增加ESP寄存器是不可用的。
正如Peter在上述评论中所述,尽管CS、SS、ES和DS都被视为零基,但这并不会以任何方式改变PUSH/POP的行为。它与任何其他段描述符的使用并没有什么不同。即使在32位多段模式下,如果将多个选择器指向相同的描述符,也可以得到重叠段。在64位模式下唯一的“更改”是,您有一个由CPU强制使用的基,RSP可以用来指向可寻址内存中的任何位置。推送/弹出操作将像往常一样工作。
操作系统如何知道特定虚拟内存地址中的数据类型(堆栈还是堆)?
用户空间程序可以(也会)随意移动堆栈和堆.操作系统并不真正需要知道堆栈和堆在哪里,但它可以在一定程度上跟踪这些堆栈,假设用户空间应用程序按照约定执行所有操作,即使用内核在程序启动时分配的堆栈,将程序中断作为堆使用。
使用内核在程序启动时分配的堆栈,或者使用mmap(2)和MAP_GROWSDOWN获得的内存区域,内核试图在内存区域超出其大小(即堆栈溢出)时自动增长内存区域,但这是有其局限性的。手动MAP_GROWSDOWN映射在实践中很少使用(参见1、2、3.、4.)。POSIX线程和其他更现代的实现对线程使用固定大小的映射。
“堆”是现代用户空间应用中一个相当抽象的概念。Linux为用户空间应用程序提供了操纵程序的基本能力,突破了brk(2)和sbrk(2),但这很少与我们现在所习惯的“堆”相对应。因此,一般来说,内核不知道应用程序的堆驻留在哪里。
不同的程序如何通过共享内存共享内核代码?
这只是通过分页来完成的。您可以说内核有一个页面表的层次结构,对于用户空间进程有许多其他的层次结构(每个任务都有一个)。当切换到内核空间(例如通过syscall)时,内核会更改CR3寄存器的值,使其指向内核的页面全局目录。当切换回用户空间时,CR3会更改为指向当前进程的页面全局目录,然后再赋予用户空间代码控制权。
https://stackoverflow.com/questions/71102775
复制相似问题