繁体   English   中英

gcc如何确定基于C的函数将使用的堆栈大小?

[英]How does the gcc determine stack size the function based on C will use?

我用C编程语言编写程序,并使用objdump将可执行文件转换为asm文件。 我不知道gcc如何确定函数将使用的堆栈大小?

    int a()
    {
         int temp[1024 * 1024];
         temp[0] = 1;
         return temp[0];
    }

这只是问题解释,忽略它是天真的。 gcc是否会为函数a分配1024 * 1024字节的空间?

如果函数有点复杂,有时会有很多局部变量,编译器如何确定堆栈大小?

首先,至少在没有优化的情况下,GCC将发出代码,在调用堆栈上分配1024 * 1024个int (不是字节;通常int是4个字节,因为sizeof(int)==4 )(即4Mbytes!)。 这可能太多了,由于堆栈溢出 ,您可能会遇到分段错误 另请参见setrlimit(2)execve(2)系统调用。

某些版本的GCC能够优化您的代码。 在Linux / Debian / Sid / x86-64上, gcc-4.8 -O3 -fverbose-asm -S stonestrong.c命令(实际上使用GCC 4.8.2)能够优化您的代码:

    .globl  a
    .type   a, @function
a:
.LFB0:
    .cfi_startproc
    movl    $1, %eax    #,
    ret
    .cfi_endproc
.LFE0:
.size   a, .-a

因此,在您的特定情况下,使用-O3优化时根本不需要堆栈帧。

编译器使用非常复杂的优化算法确定堆栈大小和布局 每个函数通常都有自己的堆栈框架。 当编译器进行优化时,调用帧的给定槽可能用于多个源代码变量,并且给定的源变量可能不需要任何堆栈槽(因为它可以保存在寄存器中),或者可能使用其中的几个(一个用于块的插槽,另一个用于另一个插槽等)。

您可能希望通过将-fdump-tree-all (将数百个文件转储!)传递给您的gcc命令来探索GCC使用的各种内部表示(特别是-fdump-tree-all )。 您可能希望使用MELT扩展GCC(通过添加新的通行证)或检查内部表示。

某些变量或某些中间值甚至不保留在堆栈中,而只保留在寄存器中。 编译器在寄存器分配上努力工作(优化时)(这是一个有自己专家的难题)。 另请参见

用C(或C ++)编码时的一般经验法则是避免使用过大的调用帧 ; 通常,您希望本地变量最多消耗不超过几千字节。

程序优化可能非常困难; 然而,目前的编译器非常擅长优化 ,如上所述。 使用GCC,您需要明确启用优化(例如,使用-O2-O3和许多其他标志)。 GCC拥有超过一千万行源代码,其中一半是中端优化(不依赖于源语言或目标处理器)。

gcc如何确定基于C的函数将使用的堆栈大小?

它通过查看所用变量的大小并添加它们来实现。 (作为第一个近似值,无论如何。出于性能和正确性的原因,对齐和填充以及可能添加到分配量中的任何其他内容。)

gcc是否会为函数a分配1024 * 1024字节的空间?

如果你告诉它这样做(你禁用优化),它很可能会。 (不是1024 * 1024字节,而是1024 * 1024 * sizeof(int)字节。至少。)但是你可以继续编译它并查看生成的程序集。

但是你的函数非常简单,它的行为很容易理解,所以我希望任何像样的编译器都能优化数组声明。 (但是,请再看一下它输出的实际装配。它可能因版本而异,有标志,有平台等)

如果函数有点复杂,有时会有很多局部变量,编译器如何确定堆栈大小?

功能的复杂性无关紧要。 如果它太复杂,那么编译器可能会做较少的优化。 但它绝对可以通过 - 添加所有变量的大小来计算必要内存的上限。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM