Cli*_*vai 3 c operating-system x86-64 segmentation-fault memory-segmentation
操作系统中的分段是一个与时间本身一样古老的概念。至少根据我的教授的说法,大多数现代操作系统已经放弃了分段的概念,现在主要依靠分页来实现内存保护,从而防止每个进程访问除自己的内存之外的任何其他内存。那么我们如何在 C 中仍然遇到“分段错误”。在现代操作系统中,我们是否仍然将分段作为一个抽象概念?
它不是C 语言中特有的东西,而是类 Unix 操作系统中的东西。任何非内存安全的语言(可以尝试访问未映射的页面)都可以编译为存在段错误的可执行文件。包括手写汇编或Fortran。但是,是的,C 和 C++ 是两种使用最广泛的非内存安全语言。
是的,这个名字很古老。Unix 很旧,当用户空间通过访问未映射的内存而导致 CPU 故障时,无需重命名为内核传递的信号。SIGSEGV这样做会破坏许多使用该常量的代码,并且仅将strerror/ 的英文文本字符串更改perror为“无效页面错误”也不会特别有帮助,尽管有可能,因为我认为这些消息已融入其中libc。但是不同的 libc 版本在转换过程中多年来都会有不同的消息,不值得这么麻烦。
在使用分页的系统中,对硬件页表中“不存在”的页面的任何访问,或者仅在尝试写入或其他情况下可读的页面,都会导致 CPU 发生异常。内核的页面错误异常处理程序检查该页面是否应该可访问,如果可以,则从磁盘将其分页,执行写入时复制或其他操作。(分别是主要或次要页面错误)。如果不是,则页面错误“无效”,并且内核向进程传递 SIGSEGV 信号。
类似地,对于一般的算术异常来说,古老的是SIGFPE(浮点异常),在大多数机器上默认情况下唯一真正可能出错的是整数除法。(默认的 FP 环境屏蔽了所有 FP 异常,因此它们只是设置粘性标志,而不是在机器代码中引发异常。)POSIX 标准要求,如果由于算术异常而要传递信号,则该信号必须是 SIGFPE。
同样,到目前为止,SIGSEGV已经被POSIX其他 Unix 标准标准化,因此在 Unix 早期,任何人都可以合理地改变它的时代早已过去了。
(某些系统还可以提供SIGBUS其他类型的错误地址错误,例如 SPARC 上的 Solaris 可以提供SIGBUS未对齐的访问。)
另请注意,某些其他类型的权限错误会重载到 SIGSEGV 上。例如,尝试lgdt在 Linux 下执行 x86 等特权指令会导致 SIGSEGV。(在这种情况下,用户空间实际上会尝试接管仍用于定义 CPU 运行模式的分段机制,例如长模式下的 16 位代码段、32 位代码段和 64 位代码段。)对于未对齐也是如此SSE SIMD 指令。所以严格来说这并不是针对无效页面错误。
可执行文件也有像文本和数据这样的“段”,其中 .text 和 .data 部分分别链接。“堆”过去大多是连续的,在 .data / .bss 之后增长(通过brk系统调用,之前mmap(MAP_ANONYMOUS)或从 /dev/zero 映射页面),因此“分段错误”术语可能并不像即使操作系统开始使用分页而不是 CPU 分段来进行内存保护,这对设计人员来说也是无稽之谈,因为可执行文件的“段”仍然映射到进程内存映像中的连续页面范围。
我不知道有关 Unix 信号命名及其在具有或不具有内存保护功能的 PDP-8 和 PDP-11 硬件上的开发的历史细节,尽管显然某些 PDP-11 型号具有某种形式的内存保护,并且甚至虚拟内存
计算机科学中有两个难题:缓存失效、命名事物和相差一错误。
| 归档时间: |
|
| 查看次数: |
711 次 |
| 最近记录: |