又是一个漫长的夜晚。我正在用C语言编写我完美的、没有bug的程序,这时可预见的事情发生了:
哦,好吧..。也许改天晚上我会更幸运地接管这个世界。但后来我突然想到。我的程序收到SIGSEGV信号并崩溃,并显示分段故障消息。这句话是从哪里来的?
我看错了吗?是否有分段保险库?#34;?还是Linux的作者犯了一个错误?这个信号不应该被命名为SIGSEGF吗?
我问我的同事,大卫·拉格很快告诉我,信号名称代表分段违规。我想这是有道理的。很久很久以前,计算机通常有内存分段。每个内存段都定义了长度-称为段限制。访问超过此限制的数据导致处理器故障。此错误代码被使用分页的较新系统重新使用。我认为英特尔手册称之为此错误";无效页面错误";。当它被触发时,它会作为SIGSEGV信号报告给用户空间。故事结束了。
Martin Levy向我指出了关于Signal";的一个古老的第6版UNIX文档。这是从1978年开始的:
UNIX树的用户空间部分(即/usr/include/signal.h)似乎很早就切换到了SIGSEGV。但是内核内部继续使用名称SIGSEG的时间要长得多。
更深入地观察,David发现PDP11陷阱向量使用了分段违规的措辞。这在UNIX历史记录库中的Research V4版中有所体现,但这并不意味着它是在V4中引入的,因为V4是第一个代码仍然可用的版本。
文件/usr/include/signal.h出现在Research V7的树中,名称为SIGSEGV。但内核当时仍称其为SIGSEG。
这就是你要的。最初,这个信号被称为SIGSEG。它随后在用户空间被重命名为SIGSEGV,稍晚一点-大约在1980年-在内核端被重命名为SIGSEGV。显然,在UNIX系统上仍然没有找到分段保管库。
至于我最初的崩溃,我当然是通过捕捉信号并跳过令人不快的指令来修复它。在Linux上,完全可以捕获和处理SIGSEGV。有了这个修复,我的代码再也不会崩溃了。当然了。
#DEFINE_GNU_SOURCE#include<;signal.h>;#include<;stdio.h>;#include<;ucontext.h>;static void sighandler(int signo,siginfo_t*si,void*v_context){ucontext_t*context=v_context;context->;uc_mcontext.gregs[REG_RIP]+=10;}int*Total_NULL_POINTER=。printf(";在NULL指针取消引用之前\n";);*TOTAL_NULL_POINTER=1;__ASM__volatile__(";nop;";);printf(";在NULL指针之后。仍然在这里!\n";);返回0;}