非常好,这个问题问得特别关键 👍,因为理解「这些段的全称」和「栈在函数执行时怎么用」是彻底搞懂 MCU 内存分布的关键。
我们分两部分来讲:
🧩 一、这些段名的全称与作用
| 段名 | 全称(英文) | 所在内存 | 主要内容 | 生命周期 |
|---|---|---|---|---|
| .text | text segment | Flash(程序存储器) | 代码(函数体、常量字符串) | 永久(程序存储期间) |
| .rodata | read-only data segment | Flash | 常量数据(const 修饰的变量、字符串常量) |
永久 |
| .data | initialized data segment | SRAM | 已初始化的全局/静态变量(带初值的) | 程序运行期间 |
| .bss | Block Started by Symbol | SRAM | 未初始化的全局/静态变量(自动清零) | 程序运行期间 |
| .heap | heap segment | SRAM | malloc()、new 动态分配的内存 |
动态分配期间 |
| .stack | stack segment | SRAM | 函数调用时的局部变量、返回地址、寄存器 | 函数调用期间 |
🧠 二、栈(Stack)的真正含义
栈是 一个共享的内存空间 ,所有函数共用同一块区域。
它并不是"每个函数一个栈",而是每个函数在这块总栈里临时分配一部分空间。
⚙️ 举例说明:
假设你在启动文件里设置:
asm
Stack_Size EQU 0x00018000 ; 96 KB
这就意味着:
整个系统的「主栈」空间总共有 96 KB,
所有函数调用、局部变量都在这 96 KB 里"挤着用"。
💻 举个具体例子:
c
void foo(void)
{
int a; // 占 4 字节
uint8_t buf[100]; // 占 100 字节
bar();
}
void bar(void)
{
uint8_t temp[200]; // 占 200 字节
}
当执行 foo() 时:
SP ───► [bar() 临时变量] 200B
[bar() 返回地址] 4B
[foo() 临时变量] 104B
...
bar() 退出后,它的 200B 就从栈中释放;
foo() 退出后,它的 104B 也释放。
整个过程都发生在同一块 96KB 的栈空间中。
📉 栈是「向下增长」的
- 栈顶地址在 SRAM 的高端(如 0x2003FFFF)
- 每次函数调用时,SP(栈指针)往低地址移动
- 函数返回时,SP 恢复到原位置
图示:
高地址 0x2003FFFF ←─ 栈顶 (__initial_sp)
↓
[foo 的局部变量]
[bar 的局部变量]
[中断上下文]
↓
低地址 0x20028000
🔍 三、你设置的 Stack_Size 是"最大允许空间"
比如你设 Stack_Size = 0x00018000 (96KB):
-
这并不是每个函数 96KB,而是:
所有函数调用层级嵌套时,总共最多可以用 96KB。
-
如果函数嵌套很深、局部变量数组很多、或者中断嵌套多层,就会更快地消耗这块空间。
📘 四、各区域的分布(完整内存图)
以 GD32F415 为例(256KB SRAM):
Flash (1MB) ────────────────────────────────
| .text / .rodata / 常量 / 程序代码 |
────────────────────────────────────────────
SRAM (256KB) ───────────────────────────────
| .data (已初始化全局变量) |
| .bss (未初始化全局变量) |
| .heap (malloc 动态分配区, 向上增长) |
| 空闲区 (heap 与 stack 缓冲) |
| .stack (函数局部变量栈, 向下增长) |
────────────────────────────────────────────
✅ 五、总结(一句话版)
| 名称 | 全称 | 作用 | 注意 |
|---|---|---|---|
| .data | Initialized Data Segment | 存全局变量(有初值) | 程序启动时从 Flash 拷贝到 SRAM |
| .bss | Uninitialized Data Segment | 存全局变量(无初值) | 启动时自动清零 |
| .heap | Heap Segment | malloc/new 动态内存 |
向上增长 |
| .stack | Stack Segment | 函数局部变量、返回地址 | 向下增长 |
| Stack_Size | 最大可用栈空间 | 全系统共用一块 | 函数嵌套越深占用越多 |
💬 简而言之:
- 你定义的
Stack_Size(比如 96KB)是整个系统共享的"总栈空间上限";- 每个函数执行时只在这块栈中"借"一点临时空间用;
- 当函数退出,这部分空间会自动释放回去。
要不要我帮你画一张 栈增长与函数调用关系的图(SP 变化示意图) ?
看一张图就能明白栈是怎么"压入"和"弹出"的。