这段代码:
int main()
{
char buffer[64];
int check;
...
如您所见,check
被声明为 AFTER buffer
,因此在堆叠中,我们必须check
ABOVE 堆栈中的buffer
对吗?
然而,当我用gdb反汇编(x86)时,这就是我得到的:
- > check
0xbffff4f8
- > buffer
0xbffff4b8
我的问题:堆栈中是否存在局部变量的特定顺序?
另外,我必须告诉你,我在另一台计算机上尝试过相同的东西(x86也是,gcc编译选项相同,但gdb版本和linux发行版不同),顺序不一样......:S < / p>
谢谢!
答案 0 :(得分:3)
gcc中有-fstack-protect
重新排序堆栈变量,默认情况下在某些Linux操作系统变体中打开了近10年,特别是Ubuntu,Redhat,gentoo。同样默认为gcc 4.8.3(&#34; 4.9及更高版本启用-fstack-protector-strong。&#34;)
关于gcc默认值的Ubuntu页面:https://wiki.ubuntu.com/ToolChain/CompilerFlags
工具链中特定于Ubuntu的默认编译器标志,用于帮助为Ubuntu提供额外的安全功能。 ... 默认标志
-fstack-protector
...首先在Ubuntu 6.10中启用。
关于堆栈保护的Ubuntu页面https://wiki.ubuntu.com/GccSsp
gcc 4.1现在附带SSP,这是一种很好的技术,可以减轻许多缓冲区溢出的可利用性。 ... SSP提供了一种技术来阻止这类漏洞的可利用性:(1)重新排序堆栈变量 ...... RedHat和gentoo默认使用SSP多年
这种重新排序需要对函数的所有局部变量进行多次O(n^2)
遍历,这将使长函数的编译速度变慢,例如&#34;为什么编译超过100,000行的std :: vector :: push_back需要很久了?&#34; - https://stackoverflow.com/a/14034393/196561
启用
-fstack-protect
时强制执行延迟分配(有时需要重新排序所有堆栈变量)。 .. cfgexpand.c
969 /* A subroutine of expand_one_var. VAR is a variable that will be
970 allocated to the local stack frame. Return true if we wish to
971 add VAR to STACK_VARS so that it will be coalesced with other
972 variables. Return false to allocate VAR immediately.
973
974 This function is used to reduce the number of variables considered
975 for coalescing, which reduces the size of the quadratic problem. */
976
977 static bool
978 defer_stack_allocation (tree var, bool toplevel)
980 /* If stack protection is enabled, *all* stack variables must be deferred,
981 so that we can re-order the strings to the top of the frame. */
因此,gcc将重新排序所有堆栈变量,字符串将位于帧的顶部。 尝试使用-fno-stack-protector
选项停用。
像往常一样,gcc的作者没有记录-fstack-protect
在公开文档https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html中的工作原理:
-fstack-protector
发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击。这是通过向具有易受攻击对象的函数添加保护变量来完成的。这包括调用alloca
的函数,以及缓冲区大于8字节的函数。输入功能时会初始化防护装置,然后在功能退出时进行检查。如果防护检查失败,则会打印一条错误消息并退出程序。
-fstack-protector-all
与-fstack-protector
类似,只是所有功能都受到保护。
-fstack-protector-strong
与-fstack-protector
类似,但包括要保护的其他函数 - 具有本地数组定义或具有本地帧地址引用的函数。
-fstack-protector-explicit
与-fstack-protector
类似,但仅保护具有stack_protect
属性的函数。
我看到的本地数组之前的唯一文档是真实的,最好的文档:源代码
https://gcc.gnu.org/viewcvs/gcc/branches/gcc-4_6-branch/gcc/cfgexpand.c?revision=175029&view=markup#l1526 - expand_used_vars()
1533 if (has_protected_decls)
1534 {
1535 /* Phase 1 contains only character arrays. */
1536 expand_stack_vars (stack_protect_decl_phase_1);
1537
1538 /* Phase 2 contains other kinds of arrays. */
1539 if (flag_stack_protect == 2)
1540 expand_stack_vars (stack_protect_decl_phase_2);
1541 }
1542
1543 expand_stack_vars (NULL);
阶段1和阶段2变量由stack_protect_decl_phase()
https://gcc.gnu.org/viewcvs/gcc/branches/gcc-4_6-branch/gcc/cfgexpand.c?revision=175029&view=markup#l1235
1235 /* Return nonzero if DECL should be segregated into the "vulnerable" upper
1236 part of the local stack frame. Remember if we ever return nonzero for
1237 any variable in this function. The return value is the phase number in
1238 which the variable should be allocated. */
1239
1240 static int
1241 stack_protect_decl_phase (tree decl)
...
1243 unsigned int bits = stack_protect_classify_type (TREE_TYPE (decl));
...
1249 if (flag_stack_protect == 2)
1250 {
1251 if ((bits & (SPCT_HAS_SMALL_CHAR_ARRAY | SPCT_HAS_LARGE_CHAR_ARRAY))
1252 && !(bits & SPCT_HAS_AGGREGATE))
1253 ret = 1;
1254 else if (bits & SPCT_HAS_ARRAY)
1255 ret = 2;
1256 }
stack_protect_classify_type
只返回HAS_ARRAY
位HAS_*_CHAR_ARRAY
仅用于char数组(char, unsigned char and signed char)