为啥 gcc 4.x 在调用方法时默认为 linux 上的堆栈保留 8 个字节?
Posted
技术标签:
【中文标题】为啥 gcc 4.x 在调用方法时默认为 linux 上的堆栈保留 8 个字节?【英文标题】:why gcc 4.x default reserve 8 bytes for stack on linux when calling a method?为什么 gcc 4.x 在调用方法时默认为 linux 上的堆栈保留 8 个字节? 【发布时间】:2011-01-24 20:07:55 【问题描述】:作为asm的初学者,我正在检查gcc -S生成的asm代码来学习。
为什么 gcc 4.x 在调用方法时默认为堆栈保留 8 个字节?
func18 是没有返回没有参数没有定义本地变量的空函数。 我不知道为什么这里保留了 8 个字节(任何论坛/网站都没有提到这个原因,人们似乎认为这是理所当然的) 是为了 %ebp 只是推动?还是返回类型?!非常感谢!
.globl _func18
_func18:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
.text
【问题讨论】:
实际上,这些指令都没有意义……没有任何局部变量的函数应该不需要设置帧指针 这可能取决于优化级别。您能否包含该函数的完整生成代码? 这不是给返回地址和栈帧指针的空间吗? thx martin & richard, richard@ 我刚刚用 -Os 做了,是的,你是对的,现在 subl $8, %esp 行不见了。但我仍然想知道它这样做的原因。我在回复中附上代码 Martin:帧指针在没有局部变量的函数中仍然有用,因此调试器可以访问函数的参数作为从%ebp
的常量偏移量。
【参考方案1】:
某些指令要求将某些数据类型对齐到多达 16 字节的边界(特别是 SSE 数据类型 __m128)。为了满足这个要求,gcc 确保堆栈最初是 16 字节对齐的,并以 16 字节的倍数分配堆栈空间。如果只需要压入一个 4 字节的返回地址和 4 字节的帧指针,则需要 8 个额外的字节来保持堆栈与 16 字节边界对齐。然而,如果 gcc 确定额外的对齐是不必要的(即没有使用花哨的数据类型并且没有调用外部函数),那么它可能会省略任何用于对齐堆栈的额外指令。确定这一点所需的分析可能需要执行某些优化过程。
另请参阅选项 -mpreferred-stack-boundary=num 的 gcc 文档。
【讨论】:
thx 标记,因此在使用 sse 进行优化时,这一切都是为了数据对齐,非常明智,因为我禁用了优化并且 subl $8 %esp 消失了。 gcc ref 非常有用!!!只有一件事,当我调整 -mpreferred-stack-boundary 时,保留只在 3 到 4 之间变化,从 4 到 12,它坚持 8 个字节,我认为保留应该是 20 个字节,不是吗? 如果你使用了 -mpreferred-stack-boundary=12,那么在任何调用外部函数的函数中,它都会以 2^12=4096 字节的倍数分配堆栈空间。如果您没有调用任何外部函数,那么它通常能够发现它生成的代码不需要保持这种对齐(取决于您的确切 gcc 版本、选项和目标架构)。 所以你的意思是在 func 不调用外部 func 的情况下,gcc 默认只保留 8 个字节? @nikcname:我在 gcc 4.4.1 (Ubuntu 9.10) 上看不到它的空函数。您使用的是什么版本和编译选项?【参考方案2】:正如上面 Richard 所说,这都是因为优化,如下所示。 但我仍然不知道为什么保留 8 个字节是优化的东西?!
原作
void func18()
int main() return 0;
编译时不指定优化标志
.text
.globl _func18
_func18:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
leave
ret
.globl _main
_main:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $0, %eax
leave
ret
.subsections_via_symbols
带 -Os 优化标志,不再保留堆栈
.text
.globl _func18
_func18:
pushl %ebp
movl %esp, %ebp
leave
ret
.globl _main
_main:
pushl %ebp
xorl %eax, %eax
movl %esp, %ebp
leave
ret
.subsections_via_symbols
【讨论】:
把这个放在你的问题中,而不是单独的答案中【参考方案3】:简单的方法:你有没有空函数调用另一个带有一个参数的函数。如果参数直接存储到堆栈中(不推送),那么这就是额外空间的用途。
【讨论】:
以上是关于为啥 gcc 4.x 在调用方法时默认为 linux 上的堆栈保留 8 个字节?的主要内容,如果未能解决你的问题,请参考以下文章