我的代码:
#include <stdio.h>
foo()
{
char buffer[8];
}
main()
{
foo();
return 0;
}
我使用gcc -ggdb -mpreferred-stack-boundary=2 -o bar bar.c
当我使用GDB ./bar
加载它时,我看到foo函数中的代码是:
sub $0x0c,$esp
为什么会这样?
我想缓冲在堆栈中占用8个字节,因此它应该是sub $0x8,$esp
!
为什么我不能将堆栈边界设置为4个字节?
帮助!
答案 0 :(得分:0)
我无法准确再现您所看到的内容,但在我的4.8.2版gcc上,该选项会影响此代码使用的堆栈数量(请确保&#34;缓冲区&#34;是用于避免它被优化掉,并修复没有返回类型/参数类型的警告):
#include <stdio.h>
void foo(void)
{
char buffer[8];
buffer[0] = 'a';
buffer[1] = '\n';
buffer[2] = 0;
printf("my first program! %s\n", buffer);
}
int main()
{
foo();
return 0;
}
使用-mpreferred-stack-boundary = 2和-mpreferred-stack-boundary = 4进行编译,并且生成的汇编程序之间的差异值得注意:
$ diff -u stb-2.s stb-4.s
--- stb-2.s 2014-04-10 09:00:39.546038191 +0100
+++ stb-4.s 2014-04-10 09:00:58.895108979 +0100
@@ -15,11 +15,11 @@
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
- subl $16, %esp
- movb $97, -8(%ebp)
- movb $10, -7(%ebp)
- movb $0, -6(%ebp)
- leal -8(%ebp), %eax
+ subl $40, %esp
+ movb $97, -16(%ebp)
+ movb $10, -15(%ebp)
+ movb $0, -14(%ebp)
+ leal -16(%ebp), %eax
movl %eax, 4(%esp)
movl $.LC0, (%esp)
.LEHB0:
@@ -67,9 +67,10 @@
.cfi_offset 5, -8
movl %esp, %ebp
.cfi_def_cfa_register 5
+ andl $-16, %esp
call _Z3foov
movl $0, %eax
- popl %ebp
+ leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
所以,至少在gcc 4.8.2中。对于x86-32,该选项有效。
当然,根据文档的默认值是-mpreferred-stack-boundary = 2,所以也许这就是为什么你不能看到&#34;没有&#34; (虽然在我的实验中,似乎它是-mpreferred-stack-boundary = 4)。 [片刻通过]啊,默认值已经随着时间的推移而改变,所以4.4.2在线文档说2,我的信息gcc for 4.8.2说4,这解释了差异。
至于为什么你的代码分配12个字节的堆栈空间 - 看看如何调用printf:
movl $.LC0, (%esp)
call printf
如果编译器可以,它将在函数的开头为函数调用预先分配参数空间,而不是像在这种情况下那样使用push $.LC0
。它没有太大的区别,但是它在printf的另一侧至少保存了一条清理指令(并且它使得处理生成的代码中的堆栈相对偏移变得更容易,因为编译器没有&#39;必须跟踪当前堆栈指针的位置 - 它始终位于函数开头的序言代码之后的一个恒定位置,一直到函数的结尾)。由于无论如何最终都需要空间,因此节省4个字节&#34;没有任何意义。