0

編集本当の質問は、投稿の最後にあり ます。gccがスタックサイズを管理する方法を理解しようとしていますが、答えが見つからない質問があります。

別の関数で関数を呼び出すと、Gcc は奇妙なことをします。余分なバイトが割り当てられますが、何のためにあるのかわかりません。

これまでで最も単純な C コードは次のとおりです。

int f(){
    int i =12;
    return 0;
}


int main(void){
    f();
    return 0;
}

そして、gdb が生成する f() の disass :

0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x10,%esp <- this part
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    $0x0,%eax
0x08048398 <+18>:    leave  
0x08048399 <+19>:    ret  

わかりました。i が int であるため、gcc は 16 バイトのアラインメント スタックを作成します (したがって 4 バイト)。gcc は i のスタックに 16 バイトを割り当てます。

しかし、f() で関数を呼び出すとすぐに、gcc が何をしているのかわかりません。新しい C コードは次のとおりです。

int g(int i){
    i=12;
    return i;
}

int f(){
    int i =12;
    g(i);
    return 0;
}


int main(void){
    f();
    return 0;
}

そして、 f() disass :

0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x14,%esp <- Here is my understanding
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    -0x4(%ebp),%eax
0x08048396 <+16>:    mov    %eax,(%esp)
0x08048399 <+19>:    call   0x8048374 <g>
0x0804839e <+24>:    mov    $0x0,%eax
0x080483a3 <+29>:    leave  
0x080483a4 <+30>:    ret

次に、gcc は 4 バイト余分に割り当てますが、f() が g() を呼び出す以上の変更はありません。

そして、これは、より多くの関数で遊ぶときに最悪になる可能性があります。

それで、この余分なバイトが何のためにあるのか、そしてgccのスタック割り当てポリシーは何なのか、知っている人はいますか?

前もって感謝します。

編集:本当の質問

わかりました申し訳ありませんが、私は質問をあまりにも速く書きました。実際、サブ 0x14 %esp で問題ありません。私の本当の理解は、このコードの一部です:

int f(){
    char i[5];
    char j[5];
    i[4]=0;
    j[4]=0;
    strcpy(i,j);
    return 0;
}


int main(void){
    f();
    return 0;
}

そして、 f() の disass :

0x080483a4 <+0>:     push   %ebp
0x080483a5 <+1>:     mov    %esp,%ebp
0x080483a7 <+3>:     sub    $0x28,%esp
0x080483aa <+6>:     movb   $0x0,-0x9(%ebp)
0x080483ae <+10>:    movb   $0x0,-0xe(%ebp)
0x080483b2 <+14>:    lea    -0x12(%ebp),%eax
0x080483b5 <+17>:    mov    %eax,0x4(%esp)
0x080483b9 <+21>:    lea    -0xd(%ebp),%eax
0x080483bc <+24>:    mov    %eax,(%esp)
0x080483bf <+27>:    call   0x80482d8 <strcpy@plt>
0x080483c4 <+32>:    mov    $0x0,%eax
0x080483c9 <+37>:    leave  
0x080483ca <+38>:    ret

スタックは次のようになります。

[oldip][oldebp][Extra(8B)][配列(10B)][並べ替えスタック(14B)][引数1(4B)][引数2(4B)]

ここでは、保存された ebp とローカル変数の間に 8 バイト余分にあることがわかります。だからここに本当に私の理解があります。

投稿が速すぎて申し訳ありませんが、迅速な回答に感謝します。

4

2 に答える 2

0
0x08048386 <+0>:     push   %ebp
0x08048387 <+1>:     mov    %esp,%ebp
0x08048389 <+3>:     sub    $0x14,%esp <- include 0x10 bytes for stack alignment and 4 byte for 1 parameter
0x0804838c <+6>:     movl   $0xc,-0x4(%ebp)
0x08048393 <+13>:    mov    -0x4(%ebp),%eax
0x08048396 <+16>:    mov    %eax,(%esp)
0x08048399 <+19>:    call   0x8048374 <g>
0x0804839e <+24>:    mov    $0x0,%eax
0x080483a3 <+29>:    leave  
0x080483a4 <+30>:    ret

ご覧のとおり、i とスタック アラインメントを含めて 16 バイトを割り当て、さらに 1 つのパラメーターに 4 バイトを割り当てると、スタックは次のようになります。

00 7f 7c 13              --> return from call address
00 00 00 00              --> this one for parameter when call g(i)  --> low address
00 00 00 00
00 00 00 00
00 00 00 00
00 00 00 0C ---> i       (ignore about edian)        --> high address 
于 2010-11-09T03:31:32.840 に答える
0

最初のケースでは、4 バイトは g() を呼び出すときに必要な 1 つのパラメーター用だと思います。2 番目のケースでは、strcpy() を呼び出すときに 2 つのパラメーターに 2 つの 4 バイト ワードが必要です。3 つのパラメーターを指定してダミー関数を呼び出し、12 バイトに変化するかどうかを確認します。

于 2010-11-09T07:15:38.047 に答える