无法设置堆栈边界gcc

标签 c gcc assembly gdb

我的c代码:

#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 字节?

救命!

最佳答案

我无法准确重现您所看到的内容,但在我的 4.8.2 版本的 gcc 上,该选项确实会影响此代码使用的堆栈量(确保使用“缓冲区”以避免它被优化掉) ,并修复无返回类型/参数类型的警告):

#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,所以也许这就是为什么你看不到与“without”有任何区别的原因(尽管在我的实验中,它似乎是 -mpreferred-堆栈边界=4)。 [瞬间过去]啊,随着时间的推移,默认值已经改变了,所以 4.4.2 在线文档说 2,我的 4.8.2 信息 gcc 说 4,这解释了差异。

至于为什么你的代码要分配 12 个字节的堆栈空间 - 看看 printf 是如何调用的:

movl    $.LC0, (%esp)
call    printf

如果编译器可以,它会在函数开始时为函数调用预先分配参数空间,而不是像本例中那样使用 push $.LC0 。这没有太大区别,但它至少在 printf 的另一侧保存了一条用于清理的指令(并且它使得在生成的代码中处理堆栈相对偏移量变得更加容易,因为编译器不必跟踪当前堆栈指针在哪里 - 它始终位于函数开头的序言代码之后的恒定位置,一直到函数的末尾)。由于无论如何最终都需要空间,因此“节省 4 个字节”是没有意义的。

关于无法设置堆栈边界gcc,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22981819/

相关文章:

c - 走近动态规划

c++ - 我无法在 namespace 范围内使用全局名称 (gcc) 声明函数

ios - 为动态链接提供后备符号

c - 微型 C 编译器链接我的程序集目标文件

windows - 具有 Virtualprotect 问题的自修改算法

assembly - 不能使用 CPU12 处理器

c - 如何输入数组

c - 如何找到多维数组中具有最大值的索引

c - [GTK]将 g_signal_connect 中的循环计数器传递给 g_callback

c++ - 派生类 : using Base class member in initializer list