为了让你对 MCU 的内存布局有一个上帝视角的理解,我们需要把物理地址空间(CPU 看到的完整地图)和逻辑数据分布(程序编译后的实际落位)结合起来看。
在经典的 ARM Cortex-M 架构(如 STM32)中,内存通常被映射到一个4GB的地址空间里。我们可以把这个空间想象成一栋大楼,不同的住户(代码、数据、外设)住在不同的楼层。
🗺️ MCU 全局物理地址分布(从低到高)
这张图展示了 CPU 视角的完整地址空间。请注意,ROM、RAM 和外设寄存器通常位于不连续的地址块中。
地址数值 (32位) 区域名称 物理介质 +-----------------------+ | 0x0000 0000 | | | ... | 代码存储区 | <-- 通常映射 Flash (ROM) | 0x1FFF FFFF | (Code Memory) | (低位地址区域) +-----------------------+ | 0x2000 0000 | | | ... | SRAM 区 | <-- 真正的 RAM | 0x3FFF FFFF | (SRAM) | (中位地址区域) +-----------------------+ | 0x4000 0000 | | | ... | 外设区 | <-- 寄存器映射区 | 0x5FFF FFFF | (Peripherals) | (高位地址区域) +-----------------------+ | 0xE000 0000 | | | ... | 内核外设 | <-- 中断控制器、SysTick | 0xFFFF FFFF | (Core Periph) | +-----------------------+🔍 详细内部布局:ROM 与 RAM
接下来,我们放大看ROM和RAM内部,代码段、数据段、堆、栈具体是如何摆放的。
1. ROM (Flash) 区域 —— 代码的“家”
地址方向:从低地址向高地址排列。
这里存放的是静态的固件镜像。
- 低位地址 (起始处):
- 中断向量表:这是 Flash 的开头(如
0x0800 0000)。它存放着“栈顶指针初始值”和“复位中断服务程序地址”。CPU 上电后第一件事就是读这里。
- 中断向量表:这是 Flash 的开头(如
- 中间部分:
- Code 段 (.text):存放编译后的机器指令(函数体)。
- RO-data 段 (.rodata):存放
const修饰的常量(如const int a = 10;)和字符串字面量(如"Hello")。
- 高位地址 (结束处):
- RW-data 的初始值:这是一个容易被忽略的区域。虽然
.data变量运行在 RAM 里,但它们的初始值(如int b = 5;中的5)必须保存在 Flash 的末尾。程序启动时,启动代码会把这部分数据搬运到 RAM 中。
- RW-data 的初始值:这是一个容易被忽略的区域。虽然
2. RAM (SRAM) 区域 —— 数据的“舞台”
地址方向:静态变量从低往高,栈从高往低。
这里存放的是运行时的动态数据。
- 低位地址 (起始处):
- RW-data 段 (.data):紧挨着 RAM 起始地址。这里存放已初始化且非零的全局/静态变量。程序一运行,这里就有了从 Flash 搬过来的值。
- BSS 段 (.bss / ZI):紧挨着
.data。这里存放未初始化或初始化为 0 的全局/静态变量。启动时会被硬件或软件清零。
- 中间部分 (动态生长区):
- 堆 (Heap):紧挨着 BSS 段,向高地址方向生长。用于
malloc或new动态分配内存。
- 堆 (Heap):紧挨着 BSS 段,向高地址方向生长。用于
- 高位地址 (顶端):
- 栈 (Stack):位于 RAM 的最高地址处,向低地址方向生长(栈底在高地址,栈顶指针往下减)。用于存放函数局部变量、函数参数、返回地址。
- 关键点:堆和栈中间是空闲内存。如果堆向上长太大,或者栈向下溢出太深,两者就会“相撞”,导致程序崩溃(Stack Overflow 或 Heap Corruption)。
📊 总结表:各段在 RAM/ROM 中的位置
表格
| 内存段 | 物理位置 | 逻辑位置 | 地址增长/方向 | 备注 |
|---|---|---|---|---|
| Code | ROM | 低地址 | 向上 | 紧接向量表 |
| RO-data | ROM | 中地址 | 向上 | 紧接 Code |
| RW-data (初值) | ROM | 高地址 | 向上 | 位于 ROM 末端 |
| RW-data (变量) | RAM | 低地址 | 向上 | 启动时从 ROM 复制而来 |
| BSS | RAM | 低地址 | 向上 | 紧接 RW-data,启动时清零 |
| Heap | RAM | 中地址 | 向上 | 动态分配,易碎片化 |
| Stack | RAM | 高地址 | 向下 | 位于 RAM 顶端,易溢出 |
一句话口诀:
“Flash 低址存代码,向量领头常量随;
RAM 低址存变量,堆往上长栈往下坠。”