You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

gcc的-fstack-usage选项对叶函数的栈使用统计是否有误?

gcc -fstack-usage对叶函数栈使用统计的异常

对比gcc的-fstack-usage选项给出的两个相似函数(一个含函数调用,一个不含)的栈使用情况时,得到了不同结果。

初始测试代码

void donothing(void) {}

void leaf(void) {
    int i = 0;
}

void noleaf(void) {
    int i = 0;
    donothing();
}

int main(void) {
    leaf();
    noleaf();

    return 0;
}

直观来看,leaf和noleaf函数局部变量相同,栈大小应一致,但-fstack-usage输出结果不同:

$ gcc -fstack-usage -o exe leaf.c
$ cat leaf.su 
leaf.c:1:6:donothing    16  static
leaf.c:3:6:leaf         16  static
leaf.c:7:6:noleaf       32  static
leaf.c:12:5:main        16  static

可见leaf函数栈大小与donothing相同,局部变量未被统计。

查看汇编代码发现,leaf和noleaf对栈的操作方式不同:

000000000000112c <leaf>:
    112c:   55                      push   %rbp
    112d:   48 89 e5                mov    %rsp,%rbp
    1130:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
    1137:   90                      nop
    1138:   5d                      pop    %rbp
    1139:   c3                      retq   

000000000000113a <noleaf>:
    113a:   55                      push   %rbp
    113b:   48 89 e5                mov    %rsp,%rbp
    113e:   48 83 ec 10             sub    $0x10,%rsp
    1142:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
    1149:   e8 d7 ff ff ff          callq  1125 <donothing>
    114e:   90                      nop
    114f:   c9                      leaveq 
    1150:   c3                      retq

noleaf通过sub $0x10,%rsp分配栈空间,leaf则直接用movl $0x0,-0x4(%rbp)存储局部变量,无预分配。但leaf的局部变量仍在栈上,为何栈使用量未统计它?


补充测试(排除callq和对齐影响)

有观点认为差异由callq和对齐要求导致,故修改代码:

void donothing(void) {}

void leaf(void) {
    { int i = 0; int j = 0; int k = 0; int l = 0; }
    { int i = 0; int j = 0; int k = 0; int l = 0; }
    { int i = 0; int j = 0; int k = 0; int l = 0; }
    { int i = 0; int j = 0; int k = 0; int l = 0; }
}

void noleaf(void) {
    { int i = 0; int j = 0; int k = 0; int l = 0; }
    { int i = 0; int j = 0; int k = 0; int l = 0; }
    { int i = 0; int j = 0; int k = 0; int l = 0; }
    { int i = 0; int j = 0; int k = 0; int l = 0; }
    donothing();
}

int main(void) {
    leaf();
    noleaf();

    return 0;
}

若差异仅由callq和对齐导致,两函数差异不应超16字节,但-fstack-usage结果如下:

su.c:1:6:donothing  16  static
su.c:3:6:leaf       16  static
su.c:10:6:noleaf    80  static
su.c:18:5:main      16  static

noleaf用80字节符合预期(64字节存局部变量,16字节存栈指针等),但leaf栈大小仍为16字节,局部变量未被统计。

对应的汇编代码如下:

000000000000112c <leaf>:
    112c:   55                      push   %rbp
    112d:   48 89 e5                mov    %rsp,%rbp
    1130:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
    1137:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)
    113e:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%rbp)
    1145:   c7 45 f0 00 00 00 00    movl   $0x0,-0x10(%rbp)
    114c:   c7 45 ec 00 00 00 00    movl   $0x0,-0x14(%rbp)
    1153:   c7 45 e8 00 00 00 00    movl   $0x0,-0x18(%rbp)
    115a:   c7 45 e4 00 00 00 00    movl   $0x0,-0x1c(%rbp)
    1161:   c7 45 e0 00 00 00 00    movl   $0x0,-0x20(%rbp)
    1168:   c7 45 dc 00 00 00 00    movl   $0x0,-0x24(%rbp)
    116f:   c7 45 d8 00 00 00 00    movl   $0x0,-0x28(%rbp)
    1176:   c7 45 d4 00 00 00 00    movl   $0x0,-0x2c(%rbp)
    117d:   c7 45 d0 00 00 00 00    movl   $0x0,-0x30(%rbp)
    1184:   c7 45 cc 00 00 00 00    movl   $0x0,-0x34(%rbp)
    118b:   c7 45 c8 00 00 00 00    movl   $0x0,-0x38(%rbp)
    1192:   c7 45 c4 00 00 00 00    movl   $0x0,-0x3c(%rbp)
    1199:   c7 45 c0 00 00 00 00    movl   $0x0,-0x40(%rbp)
    11a0:   90                      nop
    11a1:   5d                      pop    %rbp
    11a2:   c3                      retq   

00000000000011a3 <noleaf>:
    11a3:   55                      push   %rbp
    11a4:   48 89 e5                mov    %rsp,%rbp
    11a7:   48 83 ec 40             sub    $0x40,%rsp
    11ab:   c7 45 fc 00 00 00 00    movl   $0x0,-0x4(%rbp)
    11b2:   c7 45 f8 00 00 00 00    movl   $0x0,-0x8(%rbp)
    11b9:   c7 45 f4 00 00 00 00    movl   $0x0,-0xc(%rbp)
    11c0:   c7 45 f0 00 00 00 00    movl   $0x0,-0x10(%rbp)
    11c7:   c7 45 ec 00 00 00 00    movl   $0x0,-0x14(%rbp)
    11ce:   c7 45 e8 00 00 00 00    movl   $0x0,-0x18(%rbp)
    11d5:   c7 45 e4 00 00 00 00    movl   $0x0,-0x1c(%rbp)
    11dc:   c7 45 e0 00 00 00 00    movl   $0x0,-0x20(%rbp)
    11e3:   c7 45 dc 00 00 00 00    movl   $0x0,-0x24(%rbp)
    11ea:   c7 45 d8 00 00 00 00    movl   $0x0,-0x28(%rbp)
    11f1:   c7 45 d4 00 00 00 00    movl   $0x0,-0x2c(%rbp)
    11f8:   c7 45 d0 00 00 00 00    movl   $0x0,-0x30(%rbp)
    11ff:   c7 45 cc 00 00 00 00    movl   $0x0,-0x34(%rbp)
    1206:   c7 45 c8 00 00 00 00    movl   $0x0,-0x38(%rbp)
    120d:   c7 45 c4 00 00 00 00    movl   $0x0,-0x3c(%rbp)
    1214:   c7 45 c0 00 00 00 00    movl   $0x0,-0x40(%rbp)
    121b:   e8 05 ff ff ff          callq  1125 <donothing>
    1220:   90                      nop
    1221:   c9                      leaveq 
    1222:   c3                      retq   

因此,仅用callq语句无法解释两函数的栈使用差异,怀疑-fstack-usage对叶函数的统计有误。


内容的提问来源于stack exchange,提问作者Pierre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 16:57:05