GCC/Clang能否优化call stack内存占用?相关编译选项咨询
关于GCC/Clang栈帧紧凑优化的编译选项咨询
问题背景
我注意到编译器有时会在调用栈中保留无用数据。调用栈由函数栈帧(即函数调用的活动记录)组成,理想情况下栈帧应仅包含必要数据:溢出的被调用者保存寄存器、跨嵌套函数调用必须保留的局部变量、返回地址等。
考虑函数foo()调用多个其他函数的场景,foo()的活动记录大小本可以随嵌套调用的推进动态调整。以下是示例代码:
extern long f(long x); extern void bar(long x); extern void tail(void); void foo(long x) { long fx = f(x); // x必须在f(x)调用期间保留,因为后续还要用到 bar(x + fx); // 无需保留任何数据,x和fx后续不再使用 tail(); // 仅用于避免对bar(...)进行尾调用优化 }
但Clang(版本14.0.4)编译的代码并未优化栈帧使用,GCC(版本9.4.0)在启用-O2优化后的表现类似:
foo: push %rbx // 保存%rbx mov %rdi,%rbx // %rbx <- %rdi (%rbx用于保存参数x) call f // %rax <- f(%rdi) add %rax,%rbx // %rbx <- %rax + %rbx mov %rbx,%rdi // %rdi <- %rbx (从此之后%rbx已无用,x不再被使用) call bar // bar(%rdi) pop %rbx // 恢复%rbx (这一步本应更早执行) jmp tail // tail()
理想情况下,当foo()中的参数x不再有用时,应尽快释放对应的栈空间,以最小化调用栈内存占用:
foo: push %rbx // 保存%rbx mov %rdi,%rbx // %rbx <- %rdi call f // %rax <- f(%rdi) add %rax,%rbx // %rbx <- %rax + %rbx mov %rbx,%rdi // %rdi <- %rbx pop %rbx // 恢复%rbx (从栈中释放8字节空间) // (在调用bar之前执行!) call bar // bar(%rdi) jmp tail // tail()
核心提问
是否存在编译选项,能让GCC或Clang生成尽可能紧凑的栈帧,从而最小化调用栈内存占用?
性能与内存的权衡
需要明确的是,保持栈帧尽可能紧凑可能会引入额外的栈指针操作指令,甚至栈帧内的数据复制,这形成了调用栈内存占用与运行时性能之间的权衡。
较小的调用栈内存在嵌入式系统中至关重要——这类系统的RAM资源相当有限;在PC端,更小的内存占用也能带来更好的缓存局部性,进而可能提升执行速度。
我了解GCC中的-fstack-reuse选项,其默认值为all,将其改为其他值只会导致栈内存占用恶化。
更新1:修正示例
针对Jonathan提出的“x作为参数由调用方管理内存”的疑问,我更新了更合适的示例——该示例需要跨嵌套函数调用保留中间值:
extern long f(long x); extern void bar(long x); extern void tail(void); void foo(long x) { long fx = f(x); bar(fx); // fx必须在bar调用期间保留,因为后续还要用到 long ffx = f(fx); // fx在此处被再次使用 // 从此之后无需保留任何数据 // 理想情况下应在调用f()前将栈帧大小设为0 bar(ffx); tail(); }
Clang编译的汇编代码(GCC表现类似)如下:
foo: push %rbx // 保存%rbx call f // %rax <- f(%rdi) mov %rax,%rbx // %rbx <- %rax (fx被保存在%rbx中) mov %rax,%rdi // %rdi <- %rax call bar // bar(%rdi) mov %rbx,%rdi // %rdi <- %rbx (在此处再次使用fx) // (理想情况下应在此处pop) call f // %rax <- f(%rdi) ^ mov %rax,%rdi // %rdi <- %rax | call bar // bar(%rdi) | pop %rbx // 恢复%rbx ---------------------+ jmp tail
更新2:无效选项尝试
遗憾的是,-fconserve-stack、-fno-defer-pop和-foptimize-sibling-calls这些选项对上述示例均无帮助。
内容的提问来源于stack exchange,提问作者Zhiyao
相关产品推荐
相关产品推荐

