使用静态大小的数组进行堆栈保护的预期行为是啥?
Posted
技术标签:
【中文标题】使用静态大小的数组进行堆栈保护的预期行为是啥?【英文标题】:What's the expected behavior of stack protection with statically-sized arrays?使用静态大小的数组进行堆栈保护的预期行为是什么? 【发布时间】:2018-09-05 16:57:28 【问题描述】:如果我在 Ubuntu 16.04 / gcc 7.3 中编译以下内容
struct VecA
float data[4];
;
struct VecB
float x;
float y;
float z;
float w;
;
// Requires stack protection
VecA getA() return 1.0f, 1.0f, 1.0f, 1.0f;
// Does not require stack protection
VecB getB() return 1.0f, 1.0f, 1.0f, 1.0f;
像这样:
g++ -O3 -c -o result test.cpp
objdump -d result
我明白了:
0000000000000000 <_Z4getAv>:
0: 48 83 ec 18 sub $0x18,%rsp
4: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax
b: 00 00
d: 48 89 44 24 08 mov %rax,0x8(%rsp)
12: 31 c0 xor %eax,%eax
14: f3 0f 7e 05 00 00 00 movq 0x0(%rip),%xmm0 # 1c <_Z4getAv+0x1c>
1b: 00
1c: 48 8b 44 24 08 mov 0x8(%rsp),%rax
21: 64 48 33 04 25 28 00 xor %fs:0x28,%rax
28: 00 00
2a: 75 09 jne 35 <_Z4getAv+0x35>
2c: 66 0f 6f c8 movdqa %xmm0,%xmm1
30: 48 83 c4 18 add $0x18,%rsp
34: c3 retq
35: e8 00 00 00 00 callq 3a <_Z4getAv+0x3a>
3a: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1)
0000000000000040 <_Z4getBv>:
40: f3 0f 7e 05 00 00 00 movq 0x0(%rip),%xmm0 # 48 <_Z4getBv+0x8>
47: 00
48: 66 0f 6f c8 movdqa %xmm0,%xmm1
4c: c3 retq
“看起来”像 linux 堆栈保护正在应用于 VecA
。有点防御性,但我可以理解编译器是如何得出这个结论的。
但是,这就是我感到困惑的地方:
我无法在 godbolt.org 上重现此内容,即使明确启用了堆栈保护。我可以使用-fstack-protector-all
实现这两个功能,但这是意料之中的,而且无趣。
https://gcc.godbolt.org/z/ePR98P
另外,在我的系统上,显式使用堆栈保护器似乎正在删除来自getA()
的保护
g++ -O3 -c -o -fstack-protector result test.cpp
objdump -d result
0000000000000000 <_Z4getAv>:
0: f3 0f 7e 05 00 00 00 movq 0x0(%rip),%xmm0 # 8 <_Z4getAv+0x8>
7: 00
8: 66 0f 6f c8 movdqa %xmm0,%xmm1
c: c3 retq
d: 0f 1f 00 nopl (%rax)
0000000000000010 <_Z4getBv>:
10: f3 0f 7e 05 00 00 00 movq 0x0(%rip),%xmm0 # 18 <_Z4getBv+0x8>
17: 00
18: 66 0f 6f c8 movdqa %xmm0,%xmm1
1c: c3 retq
所以我的问题是:
为什么我的本地结果与 godbolt.org 上生成的结果大不相同?
我的系统行为背后是否有合理的解释?特别是关于-fstack-protector
删除保护。
断言这两个函数应该在优化代码中生成等效的程序集是合理的吗?
编辑:
完整版字符串:
g++ --version
g++ (Ubuntu 7.3.0-21ubuntu1~16.04) 7.3.0
Copyright (C) 2017 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
【问题讨论】:
C++ 没有“堆栈保护”的概念——这完全是一个 GCC 特性。可以说,c++
标签应该被删除。
@NeilButterworth 另一方面,问题是关于特定的 C++ 代码示例。
【参考方案1】:
Ubuntu 的 gcc 上的默认值为 -fstack-protector-strong
,而不是 -fstack-protector-all
。 (The gcc manual lists available options)。
https://lwn.net/Articles/584225/ 描述“强”。它真的很喜欢保护数组,但是没有数组成员的结构不能被索引,所以溢出的可能性要小得多。
On Godbolt,它为 VecA 而不是 VecB 产生堆栈保护,就像在您的桌面上一样。 (顺便说一句,你可以使用g++ -S -masm=intel -O3
来获取英特尔语法,或者objdump -drwC -Mintel
,因为你在 Godbolt 上链接到英特尔语法。)
您可以使用g++ -S -fverbose-asm -O3 foo.cpp
包含 cmets,以显示编译时 gcc 使用的所有隐含和显式选项。在 Godbolt 上,取消选中 //
图标以不隐藏 asm cmets,like this。
# GNU C++14 (GCC-Explorer-Build) version 7.3.0 (x86_64-linux-gnu)
# compiled by GNU C version 5.4.0 20160609, GMP version 6.1.0, MPFR version 3.1.4, MPC version 1.0.3, isl version isl-0.16.1-GMP
# GGC heuristics: --param ggc-min-expand=100 --param ggc-min-heapsize=131072
# options passed: -fdiagnostics-color=always -imultiarch x86_64-linux-gnu
# -iprefix /opt/compiler-explorer/gcc-7.3.0/bin/../lib/gcc/x86_64-linux-gnu/7.3.0/
# -D_GNU_SOURCE
# /tmp/compiler-explorer-compiler11885-54-1u26why.tdoy/example.cpp
# -masm=intel -mtune=generic -march=x86-64
# -auxbase-strip /tmp/compiler-explorer-compiler11885-54-1u26why.tdoy/output.s
# -g -O3 -std=gnu++14 -fstack-protector-strong -fverbose-asm
# options enabled: -faggressive-loop-optimizations -falign-labels
# -fasynchronous-unwind-tables -fauto-inc-dec -fbranch-count-reg
# -fcaller-saves -fchkp-check-incomplete-type -fchkp-check-read
# -fchkp-check-write -fchkp-instrument-calls -fchkp-narrow-bounds
# -fchkp-optimize -fchkp-store-bounds -fchkp-use-static-bounds
# -fchkp-use-static-const-bounds -fchkp-use-wrappers -fcode-hoisting
# -fcombine-stack-adjustments -fcommon -fcompare-elim -fcprop-registers
# -fcrossjumping -fcse-follow-jumps -fdefer-pop
...
【讨论】:
啊。那是我的错误,出于某种原因,我认为默认值是-fstack-protector
。以上是关于使用静态大小的数组进行堆栈保护的预期行为是啥?的主要内容,如果未能解决你的问题,请参考以下文章
静态数组仅在类定义内溢出堆栈(段错误 11),否则不会......?