0

2 つの単純な C ソース ファイルがあります。1 つ目は mainswap.c です。

void swap(int *x, int *y);

int main()
{
    int a, b;

    a = 5; 
    b = 44;
    swap(&a, &b);

    return 0;
}

void swap(int *x, int *y)
{
    int temp;

    temp = *x;
    *x = *y;
    *y = temp;
}

もう 1 つは mainfoobar.c です。

int bar(int x, int y)
{
    int z = x + y;
    return z;
}

int foo(int a, int b)
{
    return bar(a, b);
}

int main(void)
{
    foo(2, 3);
    return 0;
}

両方のリロケータブル オブジェクト ファイルを取得しました。mainそして、gcc は関数inのスタック フレームの位置合わせについて何かを行うことがわかりましたが、gcc は関数inmainswap.cに対して明示的には行いません。mainmainfoobar.c

mainswap.c のメイン:

main:
pushl   %ebp
movl    %esp, %ebp
andl    $-16, %esp
subl    $32, %esp
movl    $5, 24(%esp)
movl    $44, 28(%esp)
leal    28(%esp), %eax
movl    %eax, 4(%esp)
leal    24(%esp), %eax
movl    %eax, (%esp)
call    swap
movl    $0, %eax
leave
ret

mainfoobar.c のメイン:

main:
pushl   %ebp
movl    %esp, %ebp
subl    $8, %esp
movl    $3, 4(%esp)
movl    $2, (%esp)
call    foo
movl    $0, %eax
leave
ret

andl $-16, %espとの意図はわかるsubl $32, %esp。同じ gcc バージョン、同じオプション、同じコンピューター、唯一の違いは C ソース ファイルです。私の質問は、gcc が 2 つの主要な関数を異なる方法で扱う理由です。この現象の背後にあるものは何ですか?</p>

また、使用した gcc のバージョンは次のとおりです。

gcc (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
Copyright © 2011 Free Software Foundation, Inc.

ところで、mainmainswap.c の関数では、アラインメントと使用上の要求も満たすと思いますがsubl $16, %esp、なぜ gcc は 16 バイトを浪費するのですか?</p>

4

1 に答える 1

1

最適化を有効にせずにこれらの両方をコンパイルしたようです。そのモードでは、GCC は通常、ファイルを上から下に処理し、関数間でインライン化または最適化を試みません。ただし、関数に到達すると、知っているすべてのことを実行します。

2 つのプログラムでmainは、呼び出した関数の前または後に表示されます。ここが鍵のようです。

mainfoobar.c を次のように変更すると:

int main(void)
{
    foo(2, 3);
    return 0;
}

int bar(int x, int y)
{
    int z = x + y;
    return z;
}

int foo(int a, int b)
{
    return bar(a, b);
}

両方のバージョンの出力で、同様のスタック アライメント操作が表示されます。この 2 つの違いは、コンパイラがmainコード生成中に到達した時点で呼び出し先を認識しているかどうかにあると思われます。最初に来るときは、すべての呼び出し先の後に来るmainときよりも保守的なスタック フレームを生成します。main

どうやら SSE の出現により、GCC の 32 ビット x86 ABI は、そうでないことが証明されない限り、関数呼び出しの境界を越えて 16 バイトのアラインメントを必要とするようになりました。それがどれほど厳しいかはわかりません。そして、上記の例が示すように、GCC は、より厳密なアライメントが必要でないことを証明できる場合、アライメントを緩和します。

簡単なグーグル検索で、問題のいくつかについて説明し、他のいくつかのポインターを提供するこのリンクを見つけました。はい、これは FreeBASIC のバグ報告ですが、この問題に直接触れています。

于 2013-07-02T02:27:02.330 に答える