【问题标题】:Why exactly is "Segmentation Fault " still a thing in C为什么“分段错误”仍然是C中的一个东西
【发布时间】:2021-12-20 10:58:50
【问题描述】:

操作系统中的分段是一个与时间本身一样古老的概念。至少按照我的教授的说法,大多数现代操作系统已经放弃了分段的概念,现在主要依靠分页来实现内存保护,从而防止每个进程访问除自己之外的任何其他内存。那么我们如何仍然在 C 中遇到“分段错误”。我们是否仍然以某种方式将分段作为现代操作系统中的一个抽象概念?

【问题讨论】:

  • “segmentation fault”中的“segment”这个词与 MS-DOS 和 8086 臭名昭著的分段内存架构无关,而且至少早了十年。

标签: c operating-system segmentation-fault x86-64 memory-segmentation


【解决方案1】:

这不是在 C 中的东西,它是在类 Unix 操作系统中的东西。任何不是内存安全的语言(可以尝试访问未映射的页面)都可以编译为段错误的可执行文件。包括手写汇编或 Fortran。但是,是的,C 和 C++ 是使用最广泛的两种非内存安全语言。

是的,这个名字很古老; Unix 并且没有需要SIGSEGV重命名为内核传递的信号,当用户空间通过访问它没有访问的内存导致CPU故障时不是地图。这样做会破坏大量使用该常量的代码,并且仅将 strerror / perror 的英文文本字符串更改为“无效页面错误”也不会特别有帮助,尽管可能因为那些我认为消息已融入 libc。但是,不同的 libc 版本在转换前后几年会有不同的信息,不值得这么麻烦。

在使用分页的系统中,对硬件页表中“不存在”的页面的任何访问,或仅在您尝试写入时才可读或其他任何情况都会导致 CPU 发生异常。内核的页面错误异常处理程序检查页面是否应该可访问,如果是,则从磁盘将其分页,执行写时复制或其他操作。 (分别是主要或次要页面错误)。如果不是,则页面错误是“无效的”,内核会向进程传递一个 SIGSEGV 信号。

对于一般的算术异常,同样古老的是SIGFPE(浮点异常),在大多数机器上默认情况下唯一可以实际出错的是整数除法。 (默认的 FP 环境屏蔽了所有 FP 异常,因此它们只是设置粘性标志而不是在机器代码中引发异常。)POSIX standard requires 如果由于算术异常而要传递信号,则它必须是 SIGFPE。

同样,SIGSEGV 已经被 POSIX 和其他 Unix 标准标准化,所以在早期的 Unix 时代,任何人都可以合理地改变了早就过去了。

(某些系统还可以为其他类型的错误地址错误提供SIGBUS,例如,SPARC 上的 Solaris 为未对齐的访问提供SIGBUS。)

另请注意,某些其他类型的权限错误会重载到 SIGSEGV 上。例如,尝试在 Linux 下执行 x86 lgdt 之类的特权指令会导致 SIGSEGV。 (在这种情况下,用户空间实际上会尝试接管仍然用于定义 CPU 运行模式的分段机制,例如长模式下的 16 位、32 位和 64 位代码段。)未对齐也是如此SSE SIMD 指令。所以它不是严格来说是无效页面错误。


命名历史?

可执行文件也有像文本和数据这样的“段”,其中 .text 和 .data 部分分别链接。 “堆”过去大多是连续的,在 .data / .bss 之后增长(通过brk 系统调用,在mmap(MAP_ANONYMOUS) 或从 /dev/zero 映射页面之前),所以这可能是“分段错误”即使在操作系统开始使用分页而不是 CPU 分段来保护内存之后,这个术语对设计人员来说似乎也不是什么废话,因为可执行文件的“段”仍然映射到进程内存映像中的连续页面范围。

我不知道有关 Unix 信号命名的历史细节与它在 PDP-8 和 PDP-11 硬件上的开发(有或没有内存保护功能),尽管显然some models of PDP-11 有某种形式的内存保护,并且even virtual memory


TL:DR

There are two hard problems in computer science: Cache invalidation, and naming things 和一个错误。

【讨论】:

  • 所以本质上,这归结为我们在进程的内存映射中仍然有不同的“段”?
  • @ClintonChogo:这只是我猜测的一个可能的借口,即在维护兼容性很重要之前的早期 Unix 时代不更改名称。真正的原因可能是为了避免仅仅因为您更喜欢新名称而破坏源代码兼容性。 “Segmentation fault”仍然是贯穿其中的本质意义。但请注意我上次的更新,SIGSEGV 也可以出于其他原因交付,例如尝试在用户空间中执行仅限内核的指令,例如mov cr3, rax 尝试在 x86-64 上安装一组新的页表,如果允许的话,会让用户空间接管机器。
猜你喜欢
  • 1970-01-01
  • 2019-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多