我用C编程语言编写程序,并使用objdump将可执行文件转换为asm文件.我不知道gcc如何确定函数将使用的堆栈大小?
int a()
{
int temp[1024 * 1024];
temp[0] = 1;
return temp[0];
}
Run Code Online (Sandbox Code Playgroud)
这只是问题解释,忽略它是天真的.gcc是否会为函数a分配1024*1024字节的空间?
如果函数有点复杂,有时会有很多局部变量,编译器如何确定堆栈大小?
首先,至少在没有优化的情况下,GCC将发出代码,在调用堆栈上分配1024*1024 int-s(而不是字节;通常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
Run Code Online (Sandbox Code Playgroud)
因此,在您的特定情况下,优化时根本不需要堆栈帧-O3.
编译器使用非常复杂的优化算法确定堆栈大小和布局.每个函数通常都有自己的堆栈框架.当编译器进行优化时,调用帧的给定槽可能用于多个源代码变量,并且给定的源变量可能不需要任何堆栈槽(因为它可以保存在寄存器中),或者可能使用其中的几个(一个用于块的插槽,另一个用于另一个插槽等).
您可能希望通过传递-fdump-tree-all(将数百个文件转储!)到您的gcc命令来探索GCC使用的各种内部表示(特别是Gimple).您可能希望使用MELT扩展GCC(通过添加新的通行证)或检查内部表示.
某些变量或某些中间值甚至不保留在堆栈中,而只保留在寄存器中.编译器在寄存器分配上努力工作(优化时)(这是一个有自己专家的难题).另请参见本.
用C(或C++)编码时的一般经验法则是避免使用过大的调用帧 ; 通常,您希望本地变量最多只能消耗几千字节.
程序优化可能非常困难; 然而,目前的编译器非常擅长优化,如上所述.使用GCC,您需要明确地启用优化(例如,使用-O2或-O3许多其他标志).GCC拥有超过一千万行源代码,其中一半是中端优化(不依赖于源语言或目标处理器).