4

スタックに関連する関数呼び出しの概念に頭を悩ませようとしています。この質問は、高レベル言語ではなく、低レベル言語のコンテキストで尋ねられています。

私がこれまでに理解していることから、関数が呼び出されると、ローカル変数とパラメーターがスタック上のスタック フレームに格納されます。各スタック フレームは、1 つの関数呼び出しに関連付けられています。私がはっきりしていない部分は、誰がフレームを作成する責任があるのですか? 私のプログラムは、プログラム内の関数宣言を見て、ローカル変数をスタック上の新しいフレームに手動でコピーすることになっていますか?

4

3 に答える 3

1

通常、プロセッサ ベンダーまたはプロセッサ用の一般的な言語コンパイラを開発した最初の企業は、関数を呼び出す前に関数の呼び出し元が何をすべきか (スタックに何を入れるべきか、さまざまなレジスタに何を含めるべきかなど) と、呼び出されたものを定義します。関数は、戻る前に実行する必要があります (特定のレジスタが変更されている場合は、その値を復元するなど)。一部のプロセッサでは、複数の規則が普及しており、特定の関数のコードが、呼び出し元のコードが期待する規則を確実に使用するようにすることが一般的に非常に重要です。

レジスタの数がやや少ない 8088/8086 では、2 つの主要な規則が出現しました。C 規則は、呼び出し元が関数を呼び出す前に引数をスタックにプッシュし、後でそれらをポップする必要があることを指定します (つまり、呼び出された関数がスタックからポップオフする必要があるのは戻りアドレス)、および Pascal 規則では、呼び出された関数がリターンアドレスをポップするだけでなく、渡されたすべての引数をポップオフする必要があることを指定します。8086 では、Pascal の慣習により、わずかに小さいコードを使用できることがよくあります (スタックのクリーンアップは、関数呼び出しごとに 1 回ではなく、呼び出し可能な関数ごとに 1 回だけ行う必要があるためです。また、8086 には、指定された値をのスタックポインタリターンアドレスをポップします。Pascal 規則の欠点の 1 つは、呼び出される関数が渡されるパラメーターのバイト数を知る必要があることです。呼び出された関数が正確に正しいバイト数をポップしなかった場合、スタックの破損はほぼ確実に発生します。

多くの新しいプロセッサでは、少数の固定数のパラメーターを持つルーチンでは、通常、パラメーターがスタックにプッシュされません。代わりに、コンパイラ ベンダーは、関数が呼び出される前に最初のいくつかのパラメーターがレジスタに配置されるように指定します。これにより、多くの場合、スタックベースのパラメーターを使用して達成されるよりも優れたパフォーマンスが得られます。ただし、多くのパラメーターまたは可変引数リストを持つルーチンでは、引き続きスタックを使用する必要があります。

于 2012-05-30T21:28:16.477 に答える
0

スーパーキャットの答えを少し拡張すると、スタック フレームの設定は、呼び出し元と呼び出された関数の責任を共有します。スタック フレームは通常、ルーチンの特定の呼び出しに対してローカルなすべてのデータを参照します。次に、呼び出しルーチンは、最初にスタックベースのパラメーターをスタックにプッシュすることによって外側のスタック フレームを構築し、次にルーチンを呼び出すことによって戻りアドレスを構築します。次に、呼び出されたルーチンは、(通常) スタック上の現在のフレーム ポインターをプッシュ (保存) し、次の空きスタック スロットを指す新しいポインターを設定することによって、残りのスタック フレーム (内部スタック フレーム) を構築します。次に、スタック上のローカル変数用にスタックを予約し、使用されている言語によっては、この時点でそれらを初期化することもあります。その後、フレーム ポインターを使用して、スタックベースのパラメーターとローカル変数の両方にアクセスできます。1 つは負のオフセット、もう 1 つは正のオフセットです。ルーチンの終了時に、古いスタック フレームが復元され、ローカル データとパラメーターが削除されます。

于 2012-05-30T23:10:20.670 に答える