gcc-警告:xxxxのスタックフレームサイズを理解する


スタックフレームは、関数呼び出しが発生したときにスタック記憶空間に蓄積されたデータである.Activation Recordと呼ばれています.スタックフレームサイズは、コンパイル時に計算されます.ローカル変数、戻りaddr、パラメータなどの寸法で計算します.スタックオーバーフローをさらに予防するために、オペレーティングシステムはスタックフレームサイズを制限することができる.例えば、Linuxカーネルは、CONFIG FRAME WANに適切な値(lib/Kconfig.debug)を指定することができる.コンパイル時に関数内のスタックフレームのサイズを減らすには、malloc()などの方法でスタックにデータを格納します.
gccには-Wframe-larger-than=のオプションがあり、指定したサイズを超えた場合、警告が生成されます.GCOV KERNEL configを使用すると発生する場合があります.gcovは関数に特定のコードを挿入するため,スタックフレームワークが増加したようである.以下の実験を行います.
  • main.c
  • 
    int main(void) {
        char s[1024];
        return 0;
    }
    $ gcc -std=c99 -O0 -Wframe-larger-than=1 main.c
    main.c: In function ‘main’:
    main.c:4:1: warning: the frame size of 1040 bytes is larger than 1 bytes [-Wframe-larger-than=]
     }
     ^
    $ gcc -std=c99 -O0 -Wframe-larger-than=2048 main.c
    # No warning.
    リファレンス
  • https://stackoverflow.com/questions/2450845/what-does-this-error-mean-somefile-c200-error-the-frame-size-of-1032-bytes
  • gcov関連オプションはスタックフレームサイズをどのように増加させますか?


    gcovは、GNU Compiler Collectionに含まれるソースコードオーバーライド率分析ツールです.gccの -fprofile-arcs-ftest-coverageオプションを使用してコンパイルすると、表紙に関連するコードが挿入されコンパイルされます.このときコードサイズが増加するので,実際にどのように変化したかを実験してみる.まず,以下のコードを簡単に記述した.func関数がオプションによって変化するのを見てみましょう.
  • func_call.c
  • #include <stdio.h>
    
    int func(int val)
    {
        return val++;
    }
    
    int main(int argc, char *argv[])
    {
        func(11);
        return 0;
    }
  • Makefile
  • all: 
        gcc -Wall  func_call.c
    
    gcov_test:
        gcc -Wall -fprofile-arcs -ftest-coverage func_call.c
    
    clean:
        rm -rf a.out *.o *.gcda *.gcno

    オプションなしでコンパイルする場合


    逆アセンブリobjdump -d a.outにはfuncとmainのみが抜粋されている.総線数は192線です.
    00000000004004d6 <func>:
      4004d6:    55                       push   %rbp
      4004d7:    48 89 e5                 mov    %rsp,%rbp
      4004da:    89 7d fc                 mov    %edi,-0x4(%rbp)
      4004dd:    8b 45 fc                 mov    -0x4(%rbp),%eax
      4004e0:    8d 50 01                 lea    0x1(%rax),%edx
      4004e3:    89 55 fc                 mov    %edx,-0x4(%rbp)
      4004e6:    5d                       pop    %rbp
      4004e7:    c3                       retq   
    
    00000000004004e8 <main>:
      4004e8:    55                       push   %rbp
      4004e9:    48 89 e5                 mov    %rsp,%rbp
      4004ec:    48 83 ec 10              sub    $0x10,%rsp
      4004f0:    89 7d fc                 mov    %edi,-0x4(%rbp)
      4004f3:    48 89 75 f0              mov    %rsi,-0x10(%rbp)
      4004f7:    bf 0b 00 00 00           mov    $0xb,%edi
      4004fc:    e8 d5 ff ff ff           callq  4004d6 <func>
      400501:    b8 00 00 00 00           mov    $0x0,%eax
      400506:    c9                       leaveq 
      400507:    c3                       retq   
      400508:    0f 1f 84 00 00 00 00     nopl   0x0(%rax,%rax,1)
      40050f:    00 

    組み込みオプションのコンパイル時


    まず、組立ラインの数は基本的に多く増加しました.__gcovから始まる多くの関数が生成された.全線数は192線から2610線に増えた.
    0000000000400cc6 <func>:
      400cc6:       55                      push   %rbp 
      400cc7:       48 89 e5                mov    %rsp,%rbp
      400cca:       89 7d fc                mov    %edi,-0x4(%rbp)
      400ccd:       8b 45 fc                mov    -0x4(%rbp),%eax
      400cd0:       8d 50 01                lea    0x1(%rax),%edx
      400cd3:       89 55 fc                mov    %edx,-0x4(%rbp)
      400cd6:       90                      nop
      400cd7:       48 8b 15 82 35 20 00    mov    0x203582(%rip),%rdx        # 604260 <__gcov0.func>
      400cde:       48 83 c2 01             add    $0x1,%rdx
      400ce2:       48 89 15 77 35 20 00    mov    %rdx,0x203577(%rip)        # 604260 <__gcov0.func>
      400ce9:       5d                      pop    %rbp 
      400cea:       c3                      retq   
    
    0000000000400ceb <main>:
      400ceb:       55                      push   %rbp 
      400cec:       48 89 e5                mov    %rsp,%rbp
      400cef:       48 83 ec 10             sub    $0x10,%rsp
      400cf3:       89 7d fc                mov    %edi,-0x4(%rbp)
      400cf6:       48 89 75 f0             mov    %rsi,-0x10(%rbp)
      400cfa:       48 8b 05 4f 35 20 00    mov    0x20354f(%rip),%rax        # 604250 <__gcov0.main>
      400d01:       48 83 c0 01             add    $0x1,%rax
      400d05:       48 89 05 44 35 20 00    mov    %rax,0x203544(%rip)        # 604250 <__gcov0.main>
      400d0c:       bf 0b 00 00 00          mov    $0xb,%edi
      400d11:       e8 b0 ff ff ff          callq  400cc6 <func>
      400d16:       ba 00 00 00 00          mov    $0x0,%edx
      400d1b:       48 8b 05 36 35 20 00    mov    0x203536(%rip),%rax        # 604258 <__gcov0.main+0x8>
      400d22:       48 83 c0 01             add    $0x1,%rax
      400d26:       48 89 05 2b 35 20 00    mov    %rax,0x20352b(%rip)        # 604258 <__gcov0.main+0x8>
      400d2d:       89 d0                   mov    %edx,%eax
      400d2f:       c9                      leaveq 
      400d30:       c3                      retq   
    

  • ぶんせき
    両方ともmainがfuncを呼び出す前にsub $0x10,%rsp(スタックポインタ(rsp)をrbpから0 x 10増加させる)を行う.まずパラメータサイズは増加しません.
    上の内容を見るだけでスタックフレーム自体は増えないのではないでしょうか.

  • n/a.結論
    さらなる分析が必要だ.
  • References

  • x86 stack frame ( https://blog.kimtae.xyz/9 )
  • x 86組立システムの異なる規則CMD src dst vs CMD dst src?
  • If the registers have a % prefix → AT&T syntax → src, dst order.
    Otherwise, unadorned registers → Intel syntax → dst, src order.
    https://stackoverflow.com/questions/44684936/how-to-determine-if-the-registers-are-loaded-right-to-left-or-vice-versa
  • gcno/gcda
    https://blog.naver.com/stupidus85/70123951495