简而言之,除了在内存中使用不同的位置(因此堆栈指针寄存器的值也不同) ,以及通常不同的内存访问保护之外,什么也没有。也就是说,在用户模式下执行时,即使映射也不能访问内核内存(其中一部分是内核堆栈)。反之亦然,如果没有内核代码的明确请求(在 Linux 中,通过像 copy_from_user()这样的函数) ,用户内存(包括用户堆栈)通常不能直接访问。
为什么使用[一个单独的]内核堆栈?
特权与安全的分离。首先,用户空间程序可以使它们的堆栈(指针)任何他们想要的东西,并且通常没有架构需求甚至有一个有效的。内核因此不能 信任用户空间堆栈指针是有效的或可用的,因此将需要一个在自己控制下的集合。不同的 CPU 体系结构以不同的方式实现这一点; 当特权模式切换发生时,x86 CPU 自动切换堆栈指针,并且用于不同特权级别的值是可配置的——通过特权代码(即只有内核)。
如果在 ISR 中声明了一个局部变量,它将存储在哪里?
在内核堆栈上。内核(即 Linux 内核)执行 没有将 ISR 直接挂钩到 x86体系结构的 打断闸门,而是将中断分派委托给一个通用的内核中断进入/退出机制,该机制在调用注册处理程序之前保存预中断寄存器状态。当分派一个中断时,CPU 本身可能会执行一个特权和/或堆栈切换,这是由内核使用/设置的,因此公共中断条目代码已经可以依赖于存在的内核堆栈。
也就是说,在执行内核代码时发生的中断将只是(继续)使用此时的内核堆栈。如果中断处理程序具有深度嵌套的调用路径,这可能导致堆栈溢出(如果深度内核调用路径被中断,处理程序导致另一个深度路径; 在 Linux 中,使用 iptables 活动的网络代码中断文件系统/软件 RAID 代码,已知会在未调优的旧内核中触发这种情况... ... 解决方案是为这种工作负载增加内核堆栈大小)。