asm x86中的变量声明顺序?
Posted
技术标签:
【中文标题】asm x86中的变量声明顺序?【英文标题】:Order of variable declaration in asm x86? 【发布时间】:2016-05-12 00:33:41 【问题描述】:这里是一段代码:
int main()
char buffer[64];
int check;
...
如您所见,check
被声明为 AFTER buffer
,所以在堆栈中,我们必须在堆栈中有check
ABOVE buffer
对吧?
但是,当我用 gdb 反汇编(x86)它时,我得到了:
--> check
0xbffff4f8
--> buffer
0xbffff4b8
我的问题:局部变量的堆栈中是否有特定的顺序?
另外,我必须告诉你,我在另一台计算机上尝试过同样的事情(x86也是,相同的gcc编译选项,但不同的gdb版本和linux distrib),并且顺序不一样......:S
谢谢!
PS:如果你想了解更多细节,请看截图:(左边是电脑1,右边是电脑2)
【问题讨论】:
不,编译器不需要以任何特定顺序存储它们。如果变量适合寄存器或完全优化掉,它们甚至可能根本不在内存中。 变量可以是任意顺序,变量之前、之后或之间可以有任意数量的填充字节。 为清楚起见,填充字节用于保持对齐。 好吧,我对此有疑问...谢谢! 发布文字,而不是文字图片! 【参考方案1】:gcc 中有 -fstack-protect
用于重新排序堆栈变量,在近 10 年的一些 Linux 操作系统变体中默认开启,尤其是 Ubuntu、Redhat、gentoo。自 gcc 4.8.3 以来也是默认值(“4.9 及更高版本启用 -fstack-protector-strong。”)
关于 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)
遍历,这将使长函数的编译速度变慢,例如“为什么编译超过 100,000 行的 std::vector::push_back 需要很长时间?” - https://***.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 的作者不会在公共文档 https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html 中记录 -fstack-protect
的工作原理:
-fstack-protector
发出额外的代码来检查缓冲区溢出,例如堆栈粉碎攻击。这是通过将保护变量添加到具有易受攻击对象的函数来完成的。这包括调用alloca
的函数,以及缓冲区大于8 字节的函数。进入函数时初始化守卫,然后在函数退出时检查。如果保护检查失败,则会打印一条错误消息并退出程序。
-fstack-protector-all
与-fstack-protector
类似,只是所有功能都受到保护。
-fstack-protector-strong
与-fstack-protector
类似,但包括要保护的附加函数——那些具有本地数组定义或引用本地帧地址的函数。
-fstack-protector-explicit
与-fstack-protector
类似,但只保护那些具有stack_protect
属性的函数。
而我看到的唯一的 array-before-locals 文档是真正的、最好的文档:源代码
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)
【讨论】:
谢谢,我需要一点时间来理解您回答中的所有内容。我认为-fstack-protect
只是将金丝雀添加到堆栈中以防止基于堆栈的溢出。通过检查该金丝雀是否被覆盖。你能确认一下-fno-stack-protector
在堆栈上声明的变量顺序是否符合源文件中的声明顺序?
-fstack-protector
/ -fno-stack-protector
可能(并且将会)改变堆栈中变量的顺序。你有测试,只需用-fno-stack-protector
编译它并检查顺序。如果我的回答解决了您的问题,您可以点击“v”字接受按钮接受,也可以等待其他答案。
好的。所以如果我理解得很好,即使我们设置-fno-stack-protection
,堆栈上的变量顺序也可能会改变,对吧?我现在无法检查它,但我会尽快检查。谢谢
变量在栈上的顺序会随着-fstack-protector
而改变,而-fno-stack-protector
可能不会改变。默认是在 gcc 构建(或安装)到系统中时配置的。以上是关于asm x86中的变量声明顺序?的主要内容,如果未能解决你的问题,请参考以下文章