メモリアドレスを減らすとスタックが大きくなるという教科書を読みました。つまり、上位アドレスから下位アドレスへ。悪い質問かもしれませんが、コンセプトがよくわかりませんでした。説明できますか?
4 に答える
まず、プラットフォームに依存します。一部のアーキテクチャでは、スタックはアドレススペースの下部から割り当てられ、上に向かって大きくなります。
スタックがアドレス空間の上部から下に向かって成長するx86のようなアーキテクチャを想定すると、アイデアは非常に単純です。
=============== Highest Address (e.g. 0xFFFF)
| |
| STACK |
| |
|-------------| <- Stack Pointer (e.g. 0xEEEE)
| |
. ... .
| |
|-------------| <- Heap Pointer (e.g. 0x2222)
| |
| HEAP |
| |
=============== Lowest Address (e.g. 0x0000)
スタックを増やすには、スタックポインタを減らします。
=============== Highest Address (e.g. 0xFFFF)
| |
| STACK |
| |
|.............| <- Old Stack Pointer (e.g. 0xEEEE)
| |
| Newly |
| allocated |
|-------------| <- New Stack Pointer (e.g. 0xAAAA)
. ... .
| |
|-------------| <- Heap Pointer (e.g. 0x2222)
| |
| HEAP |
| |
=============== Lowest Address (e.g. 0x0000)
ご覧のとおり、スタックを増やすには、スタックポインターを0xEEEEから0xAAAAに減らしましたが、ヒープを増やすには、ヒープポインターを増やす必要があります。
明らかに、これはメモリレイアウトの単純化です。実際の実行可能ファイル、データセクション、...もメモリにロードされます。さらに、スレッドには独自のスタックスペースがあります。
なぜスタックが下向きに成長するのかと疑問に思うかもしれません。さて、前に言ったように、いくつかのアーキテクチャは逆になり、ヒープが下向きに成長し、スタックが上向きに成長します。スタックとヒープを反対側に配置すると、オーバーラップが防止され、十分なアドレススペースが利用可能である限り、両方の領域が自由に拡張できるため、理にかなっています。
別の有効な質問は次のようになります。プログラムはスタックポインタ自体を増減することになっていないのですか?アーキテクチャーはどのようにしてプログラマーに一方を他方に押し付けることができますか?アーキテクチャに依存するほどプログラムに依存しないのはなぜですか?アーキテクチャとほとんど戦い、スタックを反対方向に回避することはできますが、特にスタックポインタを直接変更するいくつかの命令は、call
別ret
の方向を想定して混乱を招きます。
今日、それは主にそれが長い間そのように行われてきたためであり、多くのプログラムはそれがそのように行われたと想定しており、それを変更する本当の理由はありません。
恐竜が地球を歩き回り、運が良ければコンピューターに8kBのメモリがあったとき、それは重要なスペースの最適化でした。スタックの一番下をメモリの一番上に置き、下に移動し、プログラムとそのデータを一番下に置き、malloc
領域を大きくします。このように、スタックのサイズの唯一の制限は、プログラムとヒープのサイズであり、その逆も同様です。代わりにスタックが4kB(たとえば)で始まり、成長した場合、プログラムが数百バイトのスタックしか必要としなかったとしても、ヒープが4kB(プログラムのサイズを引いたもの)より大きくなることはありません。
Man CLONE : child_stack 引数は、子プロセスが使用するスタックの場所を指定します。子プロセスと呼び出しプロセスはメモリを共有する可能性があるため、子プロセスを呼び出しプロセスと同じスタックで実行することはできません。したがって、呼び出しプロセスは、子スタックのメモリ空間を設定し、この空間へのポインタを clone() に渡す必要があります。Linux を実行するすべてのプロセッサ (HP PA プロセッサを除く) では、スタックが下向きに成長するため、child_stack は通常、子スタック用に設定されたメモリ空間の最上位アドレスを指します。