Cortex-M 详细内存布局图(地址:由低向高)

说明:
1. 为什么“向上”和“向下”增长很重要?
- 堆 (Heap) - 向上增长:当你调用
malloc()时,分配器会从.bss段结束的地方开始,寻找空闲内存,地址是越来越大的。 - 栈 (Stack) - 向下增长:这是 Cortex-M 的硬件特性(Full Descending Stack)。在启动时,
MSP指针指向 RAM 的末尾(高地址)。每当有一个函数调用、局部变量定义或发生中断压栈时,SP指针的值会减小。 - 碰撞风险 (Stack Overflow):如果你的函数嵌套太深或者局部变量分配巨大,栈指针会一路减小,直到撞上向上增长的堆或者
.bss段。这就发生了著名的栈溢出,会导致程序莫名其妙地崩溃。
2. 向量表的“特殊地位”
- 你会发现向量表始终在 Flash 的最开头(低地址)。
- 这是因为 CPU 复位瞬间,固定会去寻址
0x0000 0000(映射后的物理 Flash 地址)。它第一眼必须看到向量表。
3. .data 段的“物理隔离”
- 在 Flash 里的
.data叫 LMA (加载地址)。 - 在 RAM 里的
.data叫 VMA (运行地址)。 - 搬运工:在你的
startup_xxxx.s汇编代码中,有一段循环代码会读取 Flash 中的“变量初始值”,然后写入到 RAM 的“变量运行地址”中。
4. 栈顶指针的初始化
- 在向量表的最开头(第一个 4 字节),存放的不是代码地址,而是 初始堆栈指针 (MSP) 的数值。
- 硬件上电时,先读取这个值送到
SP寄存器,然后再读取第二个 4 字节(Reset Handler)送到PC。
小结
- 程序运行(代码/常量):在 Flash 低地址区。
- 静态数据(全局变量):在 RAM 低地址区。
- 动态数据(堆):从 RAM 低地址往高地址跑。
- 函数现场(栈):从 RAM 最高地址往低地址跑。
这种“两头往中间挤”的设计,最大限度地利用了 RAM 空间,但也带来了溢出碰撞的风险。