gcc 如何确定基于 C 的函数将使用的堆栈大小? [英] How does the gcc determine stack size the function based on C will use?

查看:16
本文介绍了gcc 如何确定基于 C 的函数将使用的堆栈大小?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I write program in C programming language, and I use objdump to translate the executable file to asm file. I have no idea how gcc determine the stack size the function will use?

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

这只是为了解释问题,忽略它是幼稚的.gcc 真的会为函数 a 分配 1024 * 1024 字节的空间吗?

It's just for problem explanation, ignore that it's naïve. Will the gcc allocate really 1024 * 1024 bytes space for function a?

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

If the function is a little complicated, sometimes a lot of local variables, how does the compiler determine the stack size?

推荐答案

首先,至少在没有优化的情况下,GCC 会发出分配 1024*1024 int-s 的代码(不是字节;通常是 int 是 4 个字节,因为 调用栈(即4Mbytes!).这可能太多了,您可能会因为 堆栈溢出.另请参阅 setrlimit(2)execve(2) 系统调用.

First, at least without optimizations, GCC will emit code that allocates 1024*1024 int-s (not bytes; often an int is 4 bytes because sizeof(int)==4) on the call stack (i.e. 4Mbytes!). This might be too much, and you might get a segmentation fault because of the stack overflow. See also the setrlimit(2) and execve(2) syscalls.

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

Some versions of GCC are able to optimize your code. On Linux/Debian/Sid/x86-64 the gcc-4.8 -O3 -fverbose-asm -S stonestrong.c command (actually using GCC 4.8.2) is able to optimize your code to:

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

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

So in your particular case, no stack frame at all is needed when optimizing with -O3.

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

The compiler determines the stack size and layout using quite complex optimization algorithms. Each function usually has its own stack frame. When the compiler is optimizing, a given slot of the call frame might be used for several source code variables, and a given source variable might not need any stack slot (because it could be kept in a register), or maybe use several of them (one slot for a block, another for another, etc...).

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

You may want to explore the various internal representations (notably Gimple) used by GCC by passing -fdump-tree-all (which will dump hundreds of files!) to your gcc command. You may want to use MELT to extend GCC (by adding your new passes) or inspect the internal representations.

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

Some variables or some intermediate values are not even kept on the stack, but only in register. The compiler works hard (when optimizing) on register allocation (which is a difficult question having its own experts). See also this.

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

A general rule of thumb when coding in C (or in C++) is to avoid too large call frames; often, you want your local variables to consume no more than a few kilobytes at most.

程序优化可能非常困难;但是,当前的编译器非常擅长优化,就像上面的那个.使用 GCC,您需要显式启用优化(例如,使用 -O2-O3 和许多其他标志).GCC有超过千万行的源代码,其中一半是中端优化(不取决于源语言或目标处理器).

Program optimization can be very hard; however current compilers are quite good at optimization like the one above. With GCC you need to enable optimizations (e.g. with -O2 or -O3 and many other flags) explicitly. GCC has more than ten millions lines of source code, and half of them are middle-end optimizations (not depending on the source language or the target processor).

这篇关于gcc 如何确定基于 C 的函数将使用的堆栈大小?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆