我的gcc版本是4.8.2,操作系统是ubuntu 14.04(64位)。 我发现有时gcc会自动生成金丝雀来进行缓冲区溢出保护,有时却不会,为什么?
生成金丝雀的情况:当 SIZE 是四的倍数时
#include<stdio.h>
#define SIZE 4
int main()
{
char s[SIZE];
scanf("%s", s);
return 0;
}
gcc -c -g -Wa,-a,-ad 后的 asm
...
4:a.c **** int main()
5:a.c **** {
13 .loc 1 5 0
14 .cfi_startproc
15 0000 55 pushq %rbp
16 .cfi_def_cfa_offset 16
17 .cfi_offset 6, -16
18 0001 4889E5 movq %rsp, %rbp
19 .cfi_def_cfa_register 6
20 0004 4883EC10 subq $16, %rsp
21 .loc 1 5 0
22 0008 64488B04 movq %fs:40, %rax
22 25280000
22 00
23 0011 488945F8 movq %rax, -8(%rbp)
24 0015 31C0 xorl %eax, %eax
6:a.c **** char s[SIZE];
7:a.c **** scanf("%s", s);
...
不生成金丝雀的情况:不是四的倍数
#include<stdio.h>
#define SIZE 2
int main()
{
char s[SIZE];
scanf("%s", s);
return 0;
}
gcc -c -g -Wa,-a,-ad 后的 asm
...
4:a.c **** int main()
5:a.c **** {
13 .loc 1 5 0
14 .cfi_startproc
15 0000 55 pushq %rbp
16 .cfi_def_cfa_offset 16
17 .cfi_offset 6, -16
18 0001 4889E5 movq %rsp, %rbp
19 .cfi_def_cfa_register 6
20 0004 4883EC10 subq $16, %rsp
6:a.c **** char s[SIZE];
7:a.c **** scanf("%s", s);
...
好吧,我想我们从评论中知道了答案,所以我将其发布在这里明确说明。
将金丝雀放入许多函数中可能会导致性能下降。这就是为什么有几种方法可以告诉 GCC 我们想要使用它们,这些方法在here中有很好的描述。主要思想:
-fstack-protector
标志的简单启发式:为使用 alloca
或大于 8
字节(默认情况下)的本地缓冲区的函数添加金丝雀。ssp-buffer-size
参数调整启发式:--param ssp-buffer-size=4
。显然 Ubuntu 发布的 GCC 版本的缓冲区大小更改为
4
,因此小于该大小的缓冲区不会触发金丝雀的生成。我确认(其他任何人都应该能够重复)通过使用 --param ssp-buffer-size=4
编译两个示例,它仅为其中之一生成带有金丝雀的程序集。