※本記事は広告を含みます。
メモリ領域解説シリーズ
本記事は「メモリ領域解説」シリーズの1つです。
組み込み開発では、プログラムや変数がどこに配置されるかを理解することが重要です。
その配置を示したものが メモリマップ です。
メモリマップを理解すると、
・text / data / bss の配置
・ROMとRAMの役割
・スタートアップコードの動作
・リンカスクリプトの意味
が一気につながります。
この記事では、メモリマップの基本をわかりやすく解説します。
ROM・FLASH・RAMの違いについてはこちらの記事で解説しています。
初心者さんメモリマップって何ですか?



プログラムや変数をメモリのどこに置くかを決めた配置図だよ。



配置って?



例えばコードはROM、変数はRAMに置くよね。
それをアドレス単位で決めたものがメモリマップ。



なるほど…メモリの設計図みたいなものですね。



そうそう、それが一番近いイメージだね。
メモリマップとは?
メモリマップとは、
ROMやRAMのどのアドレスに何を配置するかを示したものです。


例えば、次のように配置されます。
ROM(FLASH)
text
rodata
data(初期値)RAM
data
bss
heap
stackこの配置が「メモリマップ」です。
メモリマップの例
実際の組み込みシステムでは、次のようにメモリが配置されます。
ROM (Flash)
0x08000000 -----------------
text
rodata
data(初期値)
0x08010000 -----------------
RAM
0x20000000 -----------------
data
bss
heap
↓
↑
stack
0x20008000 -----------------このように、ROMとRAMは別のアドレス空間に配置されます。



heapとstackが向かい合ってますけど?



heapは上に伸びる
stackは下に伸びる
からぶつからないようにしてるんだ。



ぶつかったら?



それがスタックオーバーフローやメモリ破壊になるんだ。
heapとstackの衝突の危険についてはこちらの記事で解説しています。
ROM側のメモリ配置
ROMには「実行前から決まっているデータ」が配置されます。
text
rodata
data(初期値)それぞれ役割が違います。
text領域(プログラムコード)
ここにはプログラムの命令が配置されます。
つまり
・関数の中身
・処理の流れ
・実行されるコード
が入ります。
例
void func()
{
int a = 1;
}この処理の命令が text 領域に配置されます。
rodata領域(constデータ)
変更しないデータが配置されます。
例
const int value = 10;
const char str[] = "hello";これらは書き換えないため
ROMに配置されます。
data領域(初期値)
ここが少しややこしいです。
例
int g_value = 10;この変数は
・初期値がある
・実行時に書き換わる
という特徴があります。
そのため
初期値 → ROM
変数本体 → RAM
に分かれます。
ROMにあるdataは
初期値保存用の領域です。
RAM側のメモリ配置
RAMには「実行中に変化するデータ」が配置されます。
stack
heap
bss
dataそれぞれ役割が違います。
data領域(初期値あり変数)
初期値付きのグローバル変数が配置されます。
例
int g_value = 10;この変数は
・初期値がある
・実行中に書き換わる
ため、RAMに配置されます。
ただし初期値はROMに保存されており、
起動時にROMからRAMへコピーされます。
bss領域(未初期化変数)
初期値を持たないグローバル変数が配置されます。
例
int g_value;
static int counter;これらは起動時に
すべて0で初期化されます。
そのためROMに保存する必要がなく、
RAMのみ使用します。
heap領域(動的確保メモリ)
mallocなどで動的に確保する領域です。
例
int *p = malloc(sizeof(int));実行時にサイズが決まるため、
RAMのheap領域が使われます。
特徴
・実行時に確保
・解放が必要
・断片化が発生する
stack領域(関数呼び出し用メモリ)
関数呼び出し時に使用される領域です。
例
void func()
{
int a = 10;
}この a は stack に配置されます。
用途
・ローカル変数
・関数引数
・戻りアドレス
関数終了時に自動で解放されます。
なぜdata領域はROMとRAM両方にあるのか
初期値付き変数は次のように扱われます
ROM
初期値を保存
RAM
実行時の変数
つまり
ROM → RAM にコピーされる
この処理はスタートアップコードが行います。
スタートアップコードとの関係
電源投入時、スタートアップコードは次を実行します
① stack初期化
② data領域コピー(ROM→RAM)
③ bss領域ゼロクリア
④ main() 呼び出し
この動作はメモリマップに基づいて行われます。
スタートアップコードについてはこちらの記事で解説しています。
メモリマップは誰が決めている?
ここまで見てきたメモリ配置は、
自動的に決まっているわけではありません。
実はこの配置は リンカスクリプト によって決められています。
リンカスクリプトでは、例えば次のように指定します。
・textはROMに配置
・dataはRAMに配置
・bssはRAMに配置
・stackの開始アドレス
リンカはこの設定に従って、
プログラムや変数をメモリに配置します。
つまり
メモリマップ
= リンカスクリプトの結果
という関係になります。
リンカスクリプトについては
こちらの記事で詳しく解説します。
👉 リンカスクリプトとは?組み込みC言語のメモリ配置の仕組みを解説
まとめ
メモリマップとは
・ROMとRAMの配置図
・プログラムと変数の配置を示す
・スタートアップコードが利用する
・リンカスクリプトで決定される
組み込み開発では非常に重要な概念です。
この記事が参考になった方へ
メモリ領域については他の記事でも解説しています。
技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。
小さなご相談からでもお気軽にご連絡ください。









コメント