Linux 中的主要堆栈

Linux 中的主要堆栈

Linux 中主要的堆栈有哪些?我的意思是,例如,当发生中断时,将使用什么堆栈,用户进程堆栈和内核进程堆栈之间有什么区别?

答案1

这是高度特定于平台的。除非您绑定到某个平台(甚至 x86-32 和 x86-64 之间的差异也是主要的),否则无法回答这个问题。但是,如果将其限制为 x86,根据您最后的评论,我可以建议一些信息。

从用户态到内核态的服务请求(“系统调用”)有两种主要风格:中断风格和系统输入风格。 (这些术语是我为了描述而发明的。)中断类型的请求是处理器以与外部中断完全相同的方式处理的请求。在 x86 保护模式中,这称为使用int 0x80(较新的)或lcall 7,0(最旧的变体,SysV 兼容)并使用所谓的实现s(任务门、中断门等),配置为特殊段描述符。任务切换由处理器执行。在此切换期间,旧任务寄存器(包括堆栈指针)被存储到旧任务TSS,并且新任务寄存器(包括堆栈指针)从新任务TSS加载。换句话说,全部“通常”寄存器被存储和加载(所以这是一个非常长的动作)。 (FPU/SSE/等状态存在一个单独的问题,更改被推迟 - 有关详细信息,请参阅文档。)

为了处理此类服务请求,内核为每个线程(又名 LWP - 轻量级进程)准备一个单独的堆栈,因为可以在任何可阻止函数调用期间切换线程。这种堆栈通常具有较小的尺寸(例如4KB)。

一旦 x86 任务切换总是更改堆栈指针,就没有机会为内核重用用户态堆栈。另一方面,根本不允许这种重用(除了少量当前线程数据),因为用户进程页面可能不安全:另一个活动线程可以更改甚至取消映射它。这就是为什么简单地禁止使用用户态堆栈在内核中运行,因此,每个线程都应该有不同的用户区和内核区的堆栈;这对于现代的 sysenter 风格的处理来说仍然如此。 (另一方面,正如上面已经提到的,每个线程都应该有一个用于其内核空间的堆栈,而不是另一个线程的堆栈。)

Sysenter 风格的处理是很晚才设计出来的,并通过 SYSENTER 和 SYSCALL 处理器指令实现。它们的不同之处在于,它们在设计时没有考虑到旧的(太严格的)限制,即系统调用应保留所有寄存器。相反,它们的设计更接近于通常的函数调用 ABI,它允许函数可以任意更改某些寄存器(在大多数 ABI 中,这称为“临时”寄存器),仅更改少数寄存器并注意保留旧值由处理程序带来。 SYSENTER/SYSEXIT 指令对(32 位和 64 位)会破坏 RDX 和 RCX 的旧内容(以一种奇怪的方式 - 用户态应使用正确的值预先填充它们),并且新的 RIP 和 RSP 会从各自的 MSR 加载,因此,堆栈是立即切换到内核空间。与此相反,SYSCALL/SYSRET(仅限 64 位)使用 RCX 和 R11 作为返回地址和标志,并执行不是自己改变堆栈。随后,内核利用该堆栈的一部分来保存一些寄存器,然后切换到自己的堆栈,因为 1) 不能保证用户态堆栈足够大来保存所有需要的值,2) 出于安全原因(见上文) 。从这一点开始,我们又拥有了每线程内核堆栈。

除了用户态线程之外,还有许多仅限内核的线程(您可以在ps输出中看到它们作为方括号内的名称)。每个这样的线程都有自己的堆栈。它们实现 1) 周期性例程,在某些事件或超时时启动,2) 瞬态操作或 3) 处理实际中断处理程序请求的操作。 (对于情况 3,他们在旧内核中命名为“bh”,在新内核中命名为“ksoftirqd”。)这些线程的大部分都附加到单个逻辑 CPU。一旦他们没有用户土地,他们就没有用户土地堆栈。

AFAIK,Linux 中的外部中断处理程序仅限于每个逻辑 CPU 最多同时执行一个处理程序;在此类处理程序执行期间,不允许 IO 中断。 (NMI 是一个可怕的例外,容易出现错误处理。)它们使用任务切换中断门,并且为每个逻辑 CPU 都有一个自己的堆栈,原因与上述相同。

正如已经指出的,其中大部分内容过于特定于 x86。在其他架构中很少看到强制堆栈指针替换的任务切换。例如,ARM32 每个特权级别都有一个堆栈指针,因此,如果在内核态期间出现外部中断,堆栈指针不会更改。

由于内核开发速度很快,这个答案中的一些细节可能会被废弃。仅将其视为一般建议,并根据您将探索的具体版本进行验证。有关 x86 中断处理和任务切换的更多说明,请参阅“Intel® 64 和 IA-32 架构软件开发人员手册第 3A 卷:系统编程指南,第 1 部分”(可在 Intel 网站上免费获取)。

答案2

在 Linux 上,当在用户空间中运行时,将使用用户空间堆栈。如果进程在内核空间中运行,则它使用该进程“拥有”的内核堆栈。中断在内核中处理。

可能找到有关您最喜欢的内核的私有部分的详细信息的更好地方是在为人们编程的网站中进行翻查,例如内核新手或搜索周围低水温网络Linux 的“内核页面”。您应该能够为 BSD 或 Solaris,甚至 MacOS 找到类似的地方。 Windows 信息可能更难获得...

典型的操作系统文本中没有讨论此类信息,您必须寻找开发人员的描述。

相关内容