分段错误如何在内部(内核/硬件)工作?
Posted
技术标签:
【中文标题】分段错误如何在内部(内核/硬件)工作?【英文标题】:How does a segmentation fault work internally (kernel/hardware)? 【发布时间】:2012-12-05 20:52:11 【问题描述】:一般来说,我想知道内核(或 CPU)如何知道一个进程试图访问它没有权限的内存位置,以及名为 MMU 的神秘硬件如何帮助做到这一点。
特别是:在我看来,MMU 对操作系统内核的内存管理模型(分页、内存区域、进程地址空间......)是不可知的(我认为 Linux 和 Windows 页面并不完全是相同,例如。如果我错了,请纠正我)。但是,我的 CPU 如何判断当前代码是否可以访问位置 x
?它如何向内核发出信号?
【问题讨论】:
【参考方案1】:这可能是一个太大的话题,无法在这里完全令人满意地回答;您最好搜索一些讨论虚拟内存实现背后的硬件的论文/文章/书籍(可能从特定架构开始,因为例如 x86、x86_64、sparc 等之间存在显着差异......)。
不过,简短的回答是硬件通过页表来处理这个问题。要求 MMU 处理的每个内存访问都通过页表结构进行验证。如果描述包含所请求地址的页面的页表条目未标记为允许所请求的访问类型(读/写/执行/...),则硬件会生成一个陷阱,Linux 最终将其称为“分段错误” .其他操作系统以不同的方式命名它们(例如,一般保护故障,...)。然后操作系统内核必须找出故障的原因以及是否可以采取任何措施(许多陷阱由内核处理以从磁盘交换新页面,映射新的空页面等,但有些陷阱,例如空指针解引用,内核能做的最好的事情就是把它扔给应用程序说“你做了坏事”)。
【讨论】:
“每个内存访问...都通过页表结构进行验证” 页表结构由硬件决定——它们必须采用特定格式。通常操作系统有一定的灵活性来处理表的某些方面略有不同,但操作系统必须提供格式正确的页表供硬件使用。早期的操作系统没有使用分页,因为(a)硬件还不支持它,或者(b)硬件支持它,但是操作系统试图保持与旧系统的向后兼容性,因此实际上并没有使用它即使硬件支持它。 并且,一旦操作系统为进程设置了一次表,操作系统就不需要更改它们,除非您映射新的内存段或取消映射旧的内存段,或者需要处理带有页面输入/页面输出事件。每个内存访问(指令获取、数据读/写、堆栈等)都必须通过 MMU,但是一旦正确设置了表,硬件就会处理所有这些 - 您无需在每次访问时切换到内核. 谢谢!是否有任何现代操作系统使用不同的方法来处理虚拟内存而不是页面/页表? 不知道有没有“any”。但是,我认为前 10 名中没有任何人...【参考方案2】:MMU 被配置为(通过设计其逻辑和/或内核设置的选项位)作为分页模型实现的硬件部分。
MMU 通常必须将逻辑地址转换为映射的物理地址;当由于请求的逻辑地址没有对应的物理地址而无法这样做时,它会生成一个错误(通常作为一种中断类型),该错误会在内核中运行处理程序代码。
如果错误是试图请求理论上存在的东西——比如映射文件的一部分——但当前不存在于物理内存中,操作系统的虚拟内存实现可以通过分配一些物理内存并复制适当的磁盘块放入其中。
但是,如果是对不存在的东西的请求,则无法满足,必须作为程序错误处理。
对不允许写入的内容的写入请求将以类似方式处理。
在我的脑海中,我不确定是否在 MMU 中或在 CPU 本身中检测到执行不可执行信息的尝试;指令缓存(如果存在)如何适应这也可能使事情复杂化。但是,最终结果将是相似的 - 发生非法执行尝试的内核故障条件,内核通常会将其视为程序故障。
总而言之,该模型是更简单的硬件层告诉内核发生了异常情况,而硬件使用其当前配置无法自行处理。操作系统然后决定尝试的操作是否可以并且应该发生 - 如果是这样,它会更新硬件配置以使其成为可能。或者,如果不应该允许尝试的操作,则声明程序错误。还有其他可能性,例如,虚拟化层可以决定模拟请求的操作,而不是真正执行它,从而与硬件保持一定的隔离。
【讨论】:
以上是关于分段错误如何在内部(内核/硬件)工作?的主要内容,如果未能解决你的问题,请参考以下文章