通过GCC -fstack-check选项在C中引发了什么exception

根据gcc文档

-fstack-check 

生成代码以validation您是否超出了堆栈的边界。 请注意,此开关实际上不会导致检查完成; 操作系统必须这样做。 该开关导致生成代码以确保操作系统看到堆栈被扩展。

我的假设是这个额外的代码会产生exception,让操作系统知道。 使用C语言时,我需要知道额外代码生成了什么exception。

谷歌也没多大帮助。 关闭我知道它是在Ada语言的情况下生成Storage_Errorexception( 参考 )。

我正在开发一种小型操作系统/调度程序,我需要捕获此exception。 我正在使用C / C ++。

我的GCC版本3.4.4

它不会直接生成任何exception。 它生成的代码,当堆栈被多个页面放大时,会生成对新分配区域中每个页面的读写访问。 就是这样。 例:

 extern void bar(char *); void foo(void) { char buf[4096 * 8]; bar(buf); } 

编译(使用gcc 4.9,在x86-64上,在-O2 )到:

 foo: pushq %rbp movq $-32768, %r11 movq %rsp, %rbp subq $4128, %rsp addq %rsp, %r11 .LPSRL0: cmpq %r11, %rsp je .LPSRE0 subq $4096, %rsp orq $0, (%rsp) jmp .LPSRL0 .LPSRE0: addq $4128, %rsp leaq -32768(%rbp), %rdi call bar leave ret 

orq $0, (%rsp)orq $0, (%rsp)内存的内容没有影响,但CPU无论如何都将其视为对该地址的读写访问。 (我不知道为什么GCC在循环期间将%rsp偏移4128字节,或者为什么它认为帧指针是必要的。)理论上,操作系统可以注意到这些访问并在堆栈变得太大时做一些合适的事情。 。 对于符合POSIX的操作系统,这将是SIGSEGV信号的传递。

您可能想知道操作系统如何注意到这样的事情。 硬件允许操作系统将地址空间页面指定为完全不可访问; 任何在这些页面中读取或写入内存的尝试都会触发硬件故障,操作系统可以根据需要进行处理(同样,对于符合POSIX标准的操作系统,交付SIGSEGV )。 这可以用于将“保护区”放置在为堆栈保留的空间的末尾之前。 这就是为什么每页一次访问就足够了。

什么-fstack-check意味着保护你,明确的是,“保护区域”非常小的情况 – 可能只是一页 – 所以在堆栈上分配一个大缓冲区会使堆栈指针移该区域进入另一个可访问RAM的区域。 如果程序发生时永远不会触及保护区域内的内存,则不会立即崩溃,但是你会乱写其他区域,导致延迟动作故障。