根据gcc文档
-fstack-check
生成代码以验证您是否超出了堆栈的边界。请注意,此开关实际上不会导致检查完成;操作系统必须这样做。该开关导致生成代码以确保操作系统看到堆栈被扩展。
我的假设是这个额外的代码会产生异常以让操作系统知道。 使用C语言时,我需要知道额外代码生成了什么异常。
谷歌也没多大帮助。关闭我知道它是在Ada语言(Reference)的情况下生成Storage_Error异常。我正在开发一种小型操作系统/调度程序,我需要捕获此异常。我正在使用C / C ++。
我的GCC版本3.4.4
答案 0 :(得分:6)
它不会直接生成任何异常。它生成的代码当堆栈被多个页面放大时,会生成对新分配区域中每个页面的读写访问权限。它确实是所有。例如:
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)
对(%rsp)
处的内存内容没有影响,但CPU无论如何都将其视为对该地址的读写访问。 (我不知道为什么GCC在循环期间将%rsp
偏移4128个字节,或者为什么它认为帧指针是必要的。)
理论上,如果堆栈变得太大,操作系统可以注意到这些访问并执行适当的操作。对于符合POSIX标准的操作系统,即传递SIGSEGV
信号。
您可能想知道操作系统 如何注意到这样的事情。硬件允许操作系统将地址空间页面指定为完全不可访问;任何在这些页面中读取或写入内存的尝试都会触发操作系统可以根据需要处理的硬件故障(同样,对于符合POSIX标准的操作系统,交付SIGSEGV
)。这可用于放置一个"保护区"紧接着为堆栈保留的空间结束。这就是为什么每页一次访问就足够了。
-fstack-check
是什么意思保护你,明确的是"守卫区"非常小 - 可能只有一页 - 因此在堆栈上分配一个大缓冲区会将堆栈指针移过该区域并进入另一个可访问RAM区域。如果程序发生后永远不会触及保护区域内的内存,你就不会立即崩溃,但是你会乱写其他区域,导致延迟动作故障。