1

最初に、スタックの理解が不十分であることを示します。次に、適切に構成された回答を引き出すほど具体的ではないため、適切に回答できない、やや首尾一貫した質問をします。

では、プログラムが実行されると、関数がスタックにプッシュされます。これは、スタック ポインターがインクリメントまたはデクリメントされることを意味しますか?

スタックメモリ割り当てには正確に何が格納されていますか? 変数データへのポインタ、プログラムの est へのポインタ? スタックに正確に何が保存されているのか(どのデータ型、どの種類の参照、どのように保存されているか)を理解していないだけです。関数がローカル変数ポインターとそれを呼び出したアドレスへのポインターを保存して、返すことができると期待しています.

また、Windows x86 仮想メモリの割り当ては、実際には仮想メモリの 1 つのブロックを任意の多くの物理メモリ アドレスにマップするため、Windows x86 システムの物理メモリ内でスタックが連続しているかどうかは?

最後に、スタックが x86 上の 32 ビット ウィンドウ上のアプリケーションのユーザー割り当て仮想メモリに格納されていると仮定すると、スタック ポインター (上位または下位メモリ アドレスを参照する?) は 31 ビット (ユーザー割り当て上位 2GB はカーネル割り当て用に予約されています) リトルエンディアン参照ですね。

そして、データがスタックに到達すると (関数が入力され、新しい DWORD にメモリが割り当てられるように)、その DWORD に格納するデータがスタックにプッシュされ、スタック ポインターがインクリメントまたはデクリメントされますか? また、システムはどのようにしてスタックの両端を同時に認識しているのでしょうか?

----ここにESP?

|-変数 x の参照アドレス

|-関数 1 の変数 x のメモリ アドレスに格納される整数データ

|----関数 1 ブロック上 ^^

| |

| |

---- またはここで ESP?

ここから、参照アドレスと整数データが​​レジスタにポップされ、mov 操作によって整数データが​​割り当てられたメモリ位置に格納されますか?

新しいデータがスタックにヒットすると、スタックが「下向き」に成長すると聞いたことがありますが、メモリアドレスの上限と下限しかないため、それは不合理に思えます-スタックの一方の端だけをインクリメント/デクリメントする必要があることは理解していますが、上位アドレスまたは下位アドレス、およびスタックの長さ (高さ) はどのように区切られていますか? スタックが大きくなりすぎた場合、システムはどのように理解するのでしょうか?

質問ばかりで申し訳ありませんが、私はたくさんの本を読んできましたが、私が読んだ概念を説明するために使用された用語は、私の語彙ではうまく機能していません。また、グーグル、ウィキペディア、およびこのサイトを少し調べましたが、私の特定の懸念に対処する説明が見つかりませんでした.

ありがとう。

4

2 に答える 2

3

Ok。スタックは単なる抽象データ型です。良い。データを末尾に配置 (プッシュ) したり、データを削除 (ポップ) したりできるメモリの配列。実装方法に応じて、上または下、前面または背面から成長します。良い。

これで、(a) システム スタックがもう少し定義されました。これは、プログラムによって割り当てられたRAMの領域、またはローカルスレッドストレージなどです。ポインタはそのメモリ位置の「最後」に配置され、上に向かって成長します。プッシュは、データをスタックの現在の位置 (末尾を超えないようにデータ サイズを差し引いた値) に配置するため、書き込みの前にデクリメントします。完了すると、新しいスタック ポインタは最後に「プッシュされた」値の先頭を指します。

なぜ後方?コンベンションと使いやすさ。RAM リソースがより限られている組み込みシステムまたは一部の古いシステムを検討してください。コードと static/const データの直後にヒープを RAM の最上部に向かって開始し、同じ RAM スペースに別のタイプのストレージが必要な場合は、後ろから拡張しないのはなぜですか? これにより、各セクションの大きさを気にする必要がなくなります。それらは、すべての RAM が使用されたときにどこかで出会います (そして、次の書き込みは、スタック オーバーフローを介して急増します)。保守と作成が容易で効率的です。適切なサイズなどについて推測する必要はありません。

ここから始めてください。この時点では、仮想アドレスなどについてあまり心配する必要はありません。スペースが足りなくなったときの「ゴーブーム」部分を支援するだけです。スタックが複数のページに分割されることはないと思いますが、分割されている場合は、OS に処理させれば問題ありません (遅いですが、それはまた別の話です)。

スタックに何が入るか - あなたが望むものは何でも。通常、レジスタに収まるものを超えて関数に渡されるパラメーター、関数を超えて必要とされないスコープ変数、場合によってはこのポインターの c++ 接着剤、およびalloca()スタックを動的メモリのように扱うために使用する場合はさらに多くのことがわかります。多くの場合、これはスレッドコードで、メモリ書き込みの競合状態などを防ぐのに役立ちます。また、レジスタ内に収まらない value によって返される値は、通常、スタックにも返されます。基本的に、関数に表示されるすべてのローカル変数は、レジスタがいっぱいになり、より多くのスペースが必要になると、ある時点でスタック上に存在する可能性が高くなります。したがって、多くのシステムは、スタック メモリが可能な限り高速であることを確認しようとします。

残りの質問に答えるために-システムはスタックの両側を認識している場合と認識していない場合があります-プラットフォームによって異なります。書き込みが最後を超えた場合、Windowsは追跡を介してスタックの開始を認識していると思います。ペアになっていないプッシュ/ポップは、プログラムの 1 日を台無しにし、OS のハングを引き起こすこともあります (最近はそうではありません)。Windows 固有の 32/31 ビット アドレスに関する質問には、直接の経験がないためお答えできません。他の誰かがその部分をつかむことができます。最後に、スタックの成長方向は混乱を招く用語です。私は通常、システム スタックは「上向き」に成長していると考えていますが、それは私だけかもしれません。

これが役に立ち、いくつかの問題が解決されることを願っています!

于 2013-02-14T17:40:07.493 に答える
1

プログラムが実行されると、関数がスタックにプッシュされます - これは、スタック ポインターがインクリメントまたはデクリメントされることを意味しますか?

それは、スタックの実装方法によって異なります。メモリの末尾から逆方向に増加する場合は、デクリメントされます。メモリの先頭から前方に大きくなると、インクリメントされます。

スタックメモリ割り当てには正確に何が格納されていますか?

特定のプログラムまたはプログラミング言語がスタックにプッシュするものは何でも。これには、戻りアドレス、値の型、オブジェクトへのポインター、およびスタック フレームを含めることができます。

Windows x86の仮想メモリ割り当ては、実際には仮想メモリの単一ブロックを任意の多くの物理メモリアドレスにマップするため、Windows x86システムの物理メモリでスタックが連続しているかどうかは?

ここを参照してください: http://www.dirac.org/linux/gdb/02a-Memory_Layout_And_The_Stack.php

スタックが大きくなりすぎた場合、システムはどのように理解するのでしょうか?

ヒープの一番上に到達します。

于 2013-02-14T17:40:20.120 に答える