MCU程序段的分类
程序的下载(烧录到存储器中)通常是按照程序文件分段(Code段、RO_data段、RW_data段、ZI_data段)的方式存储的,但运行时内存的布局会按照程序进程分段(TEXT段、DATA段、BSS段、堆栈段)进行组织。以下是具体分析:
1. 下载时的存储方式(文件分段)
程序在编译链接后生成的二进制文件(如ELF、Hex、Bin等)是按文件分段存储的,主要包括:
- Code段:存储机器指令(代码)。
- RO_data段:存储只读常量(如字符串常量、const变量)。
- RW_data段:存储已初始化且非零的全局/静态变量。
- ZI_data段:存储未初始化或初始化为零的全局/静态变量(实际下载时可能不占用空间,仅记录大小)。
下载时的特点:
- 文件中的
ZI_data段
通常不会直接存储零值数据,而是通过链接脚本记录其大小,运行时由启动代码(如startup.s
)在内存中初始化为零。 - 下载到Flash/ROM时,仅包含
Code
、RO_data
和RW_data
的初始值,ZI_data
仅保留大小信息。
2. 运行时的内存布局(进程分段)
程序运行时,会根据进程分段加载到内存中:
- TEXT段:对应文件中的
Code段
和RO_data段
,通常加载到只读内存(如Flash或ROM)。 - DATA段:对应文件中的
RW_data段
,需从Flash拷贝到可读写内存(如RAM),因为运行时可能需要修改这些变量。 - BSS段:对应文件中的
ZI_data段
,由启动代码在RAM中初始化为零。 - HEAP和STACK:在运行时动态分配,不占用下载文件空间。
关键区别:
RW_data段
在文件中存储初始值,但运行时需要复制到RAM的DATA段
(因为Flash不可写)。ZI_data段
在文件中仅记录大小,运行时在RAM的BSS段
中分配并清零。
3. 为什么下载按文件分段?
- 存储效率:Flash/ROM空间有限,避免存储全零的
ZI_data
数据。 - 执行效率:启动时只需从Flash中拷贝
RW_data
的初始值到RAM,并快速清零BSS段
。
4. 链接脚本的作用
链接脚本(如ld
文件)会明确指定:
- 哪些段属于Flash(
Code
、RO_data
、RW_data
的初始值)。 - 哪些段属于RAM(
RW_data
的运行地址、BSS段
的分配)。
示例链接脚本片段:
MEMORY {FLASH (rx) : ORIGIN = 0x08000000, LENGTH = 256KRAM (rwx) : ORIGIN = 0x20000000, LENGTH = 64K
}SECTIONS {.text : { *(.text*) } > FLASH /* Code段 */.rodata : { *(.rodata*) } > FLASH /* RO_data段 */.data : { *(.data*) } > RAM AT > FLASH /* RW_data段:RAM中运行,Flash中存储初始值 */.bss : { *(.bss*) } > RAM /* ZI_data段 */
}
5. 总结
- 下载时:按文件分段(Code、RO_data、RW_data、ZI_data)存储到Flash/ROM。
- 运行时:按进程分段(TEXT、DATA、BSS、堆栈)组织内存,其中
RW_data
和ZI_data
需从Flash初始化到RAM。
这种设计平衡了存储空间和运行时效率,是嵌入式系统和裸机程序的典型实现方式。