他の答えに加えて、スタックとヒープスペースの間にRAMを作成するときは、静的な非定数データ(ファイルグローバル、関数静的、プログラム全体など)のスペースも考慮する必要があることを付け加えます。 Cの観点からのグローバル、およびおそらくC ++のその他)。
スタック/ヒープ割り当ての仕組み
スタートアップアセンブリファイルは、領域を定義する1つの方法であることに注意してください。ツールチェーン(ビルド環境とランタイム環境の両方)は、スタック空間の開始(ベクターテーブルに初期スタックポインターを格納するために使用)とヒープ空間の開始と終了(ダイナミックによって使用される)メモリアロケータ、通常はlibcによって提供されます)
OPの例では、1kiBのスタックサイズと0Bのヒープサイズの2つのシンボルのみが定義されています。これらの値は他の場所で使用され、実際にスタックとヒープスペースを生成します
@Gillesの例では、サイズが定義され、アセンブリファイルで使用されて、どこからでもスタックスペースを設定し、スタックStack_Memで識別され、末尾にラベル__initial_spを設定します。同様に、ヒープについても、スペースはシンボルHeap_Mem(サイズは0.5kiB)ですが、先頭と末尾にラベルがあります(__heap_baseおよび__heap_limit)。
これらはリンカによって処理され、メモリは(Stack_MemおよびHeap_Memシンボルによって)占有されているため、スタックスペースとヒープスペース内には何も割り当てられませんが、それらのメモリとすべてのグローバルを必要な場所に配置できます。ラベルは、指定されたアドレスで長さのないシンボルになります。__initial_spはリンク時にベクターテーブルに直接使用され、__ heap_baseおよび__heap_limitはランタイムコードによって使用されます。シンボルの実際のアドレスは、リンカーが配置した場所に基づいてリンカーによって割り当てられます。
上記で説明したように、これらのシンボルは実際にはstartup.sファイルから取得する必要はありません。これらはリンカ設定(Keilのスキャッタロードファイル、GNUのリンカスクリプト)から取得でき、それらの場合、配置をよりきめ細かく制御できます。たとえば、スタックをRAMの先頭または末尾に強制的に配置したり、グローバルをヒープから遠ざけたり、必要なものを配置したりできます。HEAPまたはSTACKが、グローバルが配置された後に残っているRAMを占有するように指定することもできます。ただし、他のメモリが減少するほど静的変数を追加することに注意する必要があります。
ただし、各ツールチェーンは異なり、構成ファイルの記述方法と動的メモリアロケータが使用するシンボルは、特定の環境のドキュメントから取得する必要があります。
スタックサイズ
スタックサイズの決定方法については、再帰または関数ポインターを使用しない場合、多くのツールチェーンがプログラムの関数呼び出しツリーを分析することで最大のスタック深度を提供できます。これらを使用する場合、スタックサイズを推定し、カーディナル値を事前に入力し(おそらくmainの前にエントリ関数を使用して)、その後、プログラムがしばらく実行された後、最大深度がどこにあるかを確認します(これはカーディナル値の場所です)終わり)。プログラムを限界まで完全に実行した場合、スタックを縮小できるかどうか、またはプログラムがクラッシュしたり、基本値が残っていない場合は、スタックを増やして再試行する必要があるかどうかをかなり正確に知ることができます。
ヒープサイジング
ヒープサイズの決定は、もう少しアプリケーションに依存します。起動時にのみ動的割り当てを行う場合は、起動コードに必要なスペースを追加できます(さらに、メモリ管理のためのオーバーヘッドも追加できます)。メモリマネージャのソースにアクセスできる場合は、オーバーヘッドが正確にわかります。また、メモリをウォークして使用情報を提供するコードを記述することもできます。動的ランタイムメモリを必要とするアプリケーション(インバウンドイーサネットフレーム用のバッファの割り当てなど)については、スタックサイズを慎重に調整し、スタックおよび静的スタックの後に残っているすべてをヒープに提供することをお勧めします。
最終ノート(RTOS)
OPの質問はベアメタル用にタグ付けされましたが、RTOS用のメモを追加したいと思います。多くの場合(常に?)、各タスク/プロセス/スレッド(簡単にするためにここでタスクを書きます)には、タスクの作成時にスタックサイズが割り当てられます。タスクスタックに加えて、小さなOSもあります。スタック(割り込みなどに使用)
タスクアカウンティング構造とスタックはどこかから割り当てる必要があり、これは多くの場合、アプリケーションの全体的なヒープ領域からのものです。これらのインスタンスでは、OSは初期化時にのみ使用するため、初期スタックサイズは重要ではありません。たとえば、リンク中に残りのすべてのスペースをHEAPに割り当て、ヒープの最後に初期スタックポインターを配置してヒープに成長させ、OSがヒープの先頭から割り当てを開始することを知り、 initial_spスタックを放棄する直前にOSスタックを割り当てます。次に、すべてのスペースが、タスクスタックおよびその他の動的に割り当てられたメモリの割り当てに使用されます。