尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
嵌入式:Keil的Code、RW、RO、ZI段的解析
相关阅读嵌入式https://blog.csdn.net/weixin_45791458/category_12768532.html// 例1 int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */ delay_init(72); /* 初始化延时函数 */ led_init(); /* 初始化LED */ while(1) { LED0(0); /* LED0 亮 */ LED1(1); /* LED1 灭 */ delay_ms(500); LED0(1); /* LED0 灭 */ LED1(0); /* LED1 亮 */ delay_ms(500); } }假设以例1所示的程序为例在Keil编译它后编译信息会有如下所示的提示。Program Size: Code5282 RO-data362 RW-data28 ZI-data1900在项目映射文件的底部也可以找到类似的信息。 Code (inc. data) RO Data RW Data ZI Data Debug 5282 292 362 28 1900 513189 Grand Totals 5282 292 362 28 1900 513189 ELF Image Totals 5282 292 362 28 0 0 ROM Totals Total RO Size (Code RO Data) 5644 ( 5.51kB) Total RW Size (RW Data ZI Data) 1928 ( 1.88kB) Total ROM Size (Code RO Data RW Data) 5672 ( 5.54kB) 本文就将详细阐述Keil的Code、RW、RO、ZI段所有的实验在ARM编译器5下进行。Code段通俗来讲Code段存储了指令因为程序的指令在运行过程中通常不需要修改这个段通常是只读的所以被存放在非易失性存储器中ROM、Flash等。例2在例1的基础上增加了一个新的函数并调用了它。void func(void) { LED0(0); /* LED0 亮 */ return; } int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */ delay_init(72); /* 初始化延时函数 */ led_init(); /* 初始化LED */ while(1) { LED0(0); /* LED0 亮 */ func(); LED1(1); /* LED1 灭 */ delay_ms(500); LED0(1); /* LED0 灭 */ LED1(0); /* LED1 亮 */ delay_ms(500); } }此时的编译结果如下所示可以看到除了Code段有增加其他段都没有变化。Program Size: Code5310 RO-data362 RW-data28 ZI-data1900由于现在很多单片机采用XIP的方式执行程序因此不再需要将Code段的代码从非易失性存储器搬到RAM中进行执行了。RW段RW段存储了可读写数据存放有初始值且没有const关键词修饰的全局变量和静态变量这些变量的值需要保存在非易失性存储器中在程序启动时会从非易失性存储器复制到RAM中这个过程由Code段内的一些初始化函数完成并且在程序运行时可以读写。需要特别注意的是即使是函数内的静态变量也是保存在RW段的这代表着即使函数还未被调用它内部的静态变量就已经存在了。例3在例1的基础上增加了一个有初始值的全局变量和静态变量没有const关键词修饰。// 例3 int a __attribute__((used)) 11111; int main(void) { static int b __attribute__((used)) 11111; HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */ delay_init(72); /* 初始化延时函数 */ led_init(); /* 初始化LED */ while(1) { LED0(0); /* LED0 亮 */ LED1(1); /* LED1 灭 */ delay_ms(500); LED0(1); /* LED0 灭 */ LED1(0); /* LED1 亮 */ delay_ms(500);; } }__attribute__((used))属性强制告诉编译器这个变量必须保留即使它没有被显式使用。此时的编译结果如下所示可以看到RW段增加了8也就是两个int类型数据所占用的空间。Program Size: Code5282 RO-data362 RW-data36 ZI-data1900RO段RO段存储了只读数据存放有初始值且被const关键词修饰的全局变量和有初始值且被const关键词修饰、用指针指向的字符串字面量、printf/scanf函数中的格式字符串。这些值需要保存在非易失性存储器中在程序启动时会从非易失性存储器复制到RAM中这个过程由Code段内的一些初始化函数完成并且在程序运行时只读。例4在例1的基础上增加了一个有初始值且被const关键词修饰的全局变量和静态变量一个指针指向的字符串字面量。// 例4 const int a __attribute__((used)) 11111; char * str __attribute__((used)) 123; int main(void) { const static int b __attribute__((used)) 11111; HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */ delay_init(72); /* 初始化延时函数 */ led_init(); /* 初始化LED */ while(1) { LED0(0); /* LED0 亮 */ LED1(1); /* LED1 灭 */ delay_ms(500); LED0(1); /* LED0 灭 */ LED1(0); /* LED1 亮 */ delay_ms(500);; } }此时的编译结果如下所示但是RO段只增加了10而不是预计的12且Code段增加了2它应该不变才对。Program Size: Code5284 RO-data372 RW-data32 ZI-data1896要弄清楚为什么会有这种情况需要去看项目映射文件下面列出了例1和例4的.map文件。// 例1的.map文件 Image component sizes Code (inc. data) RO Data RW Data ZI Data Debug Object Name 102 10 0 4 0 1787 delay.o 144 12 0 0 0 879 led.o 108 10 0 0 0 452503 main.o 64 26 304 0 1536 920 startup_stm32f103xe.o 154 32 0 9 0 6279 stm32f1xx_hal.o 272 22 0 0 0 28702 stm32f1xx_hal_cortex.o 424 10 0 0 0 1215 stm32f1xx_hal_dma.o 844 40 0 0 0 2664 stm32f1xx_hal_gpio.o 1708 84 0 0 0 4336 stm32f1xx_hal_rcc.o 796 6 0 0 0 6287 stm32f1xx_hal_uart.o 32 0 0 0 0 3762 stm32f1xx_it.o 102 0 0 0 0 699 sys.o 2 0 24 4 0 1295 system_stm32f1xx.o 176 28 0 7 264 3541 usart.o ---------------------------------------------------------------------- 4938 280 362 28 1800 514869 Object Totals 0 0 32 0 0 0 (incl. Generated) 10 0 2 4 0 0 (incl. Padding) ---------------------------------------------------------------------- Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name 8 0 0 0 0 68 __main.o 0 0 0 0 0 0 __rtentry.o 12 0 0 0 0 0 __rtentry2.o 6 0 0 0 0 0 __rtentry4.o 52 8 0 0 0 0 __scatter.o 26 0 0 0 0 0 __scatter_copy.o 28 0 0 0 0 0 __scatter_zi.o 18 0 0 0 0 80 exit.o 6 0 0 0 0 152 heapauxi.o 2 0 0 0 0 0 libinit.o 2 0 0 0 0 0 libinit2.o 2 0 0 0 0 0 libshutdown.o 2 0 0 0 0 0 libshutdown2.o 8 4 0 0 96 68 libspace.o 78 0 0 0 0 80 rt_memclr_w.o 2 0 0 0 0 0 rtexit.o 10 0 0 0 0 0 rtexit2.o 74 0 0 0 0 80 sys_stackheap_outer.o 2 0 0 0 0 68 use_no_semi.o 2 0 0 0 0 68 use_no_semi_2.o ---------------------------------------------------------------------- 344 12 0 0 100 664 Library Totals 4 0 0 0 4 0 (incl. Padding)// 例4的.map文件 Image component sizes Code (inc. data) RO Data RW Data ZI Data Debug Object Name 102 10 0 4 0 1787 delay.o 144 12 0 0 0 879 led.o 108 10 12 4 0 452755 main.o 64 26 304 0 1536 920 startup_stm32f103xe.o 154 32 0 9 0 6279 stm32f1xx_hal.o 272 22 0 0 0 28702 stm32f1xx_hal_cortex.o 424 10 0 0 0 1215 stm32f1xx_hal_dma.o 844 40 0 0 0 2664 stm32f1xx_hal_gpio.o 1708 84 0 0 0 4336 stm32f1xx_hal_rcc.o 796 6 0 0 0 6287 stm32f1xx_hal_uart.o 32 0 0 0 0 3762 stm32f1xx_it.o 102 0 0 0 0 699 sys.o 2 0 24 4 0 1295 system_stm32f1xx.o 176 28 0 7 264 3541 usart.o ---------------------------------------------------------------------- 4940 280 372 32 1800 515121 Object Totals 0 0 32 0 0 0 (incl. Generated) 12 0 0 4 0 0 (incl. Padding) ---------------------------------------------------------------------- Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name 8 0 0 0 0 68 __main.o 0 0 0 0 0 0 __rtentry.o 12 0 0 0 0 0 __rtentry2.o 6 0 0 0 0 0 __rtentry4.o 52 8 0 0 0 0 __scatter.o 26 0 0 0 0 0 __scatter_copy.o 28 0 0 0 0 0 __scatter_zi.o 18 0 0 0 0 80 exit.o 6 0 0 0 0 152 heapauxi.o 2 0 0 0 0 0 libinit.o 2 0 0 0 0 0 libinit2.o 2 0 0 0 0 0 libshutdown.o 2 0 0 0 0 0 libshutdown2.o 8 4 0 0 96 68 libspace.o 78 0 0 0 0 80 rt_memclr_w.o 2 0 0 0 0 0 rtexit.o 10 0 0 0 0 0 rtexit2.o 74 0 0 0 0 80 sys_stackheap_outer.o 2 0 0 0 0 68 use_no_semi.o 2 0 0 0 0 68 use_no_semi_2.o ---------------------------------------------------------------------- 344 12 0 0 96 664 Library Totals 4 0 0 0 0 0 (incl. Padding)从中可以看出main.c编译得到的目标文件main.o中code段大小是108没有改变而RO段确实从0变成了12。问题在于例4的Code段的(incl. Padding)从10变成了12因此造成了整体的Code段增加了2例4的RO段的(incl. Padding)从2变成了0因此造成了整体的RO段只增加了10。ZI段ZI段存储了读写数据存放没有初始值的全局变量和有初始值且被const关键词修饰。这些值不需要保存在非易失性存储器中在程序启动时会直接在RAM中初始化为0这个过程由Code段内的一些初始化函数完成。例5在例1的基础上增加了一个无初始值的全局变量。// 例5 int b __attribute__((used)); int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟,72M */ delay_init(72); /* 初始化延时函数 */ led_init(); /* 初始化LED */ while(1) { LED0(0); /* LED0 亮 */ LED1(1); /* LED1 灭 */ delay_ms(500); LED0(1); /* LED0 灭 */ LED1(0); /* LED1 亮 */ delay_ms(500); } }奇怪的是似乎编译器将无初始值的全局变量放在了RW段如下所示这点尚不明确希望有懂的大佬告诉我。// 例5的.map文件 Image component sizes Code (inc. data) RO Data RW Data ZI Data Debug Object Name 102 10 0 4 0 1787 delay.o 144 12 0 0 0 879 led.o 120 12 0 4 0 452703 main.o 64 26 304 0 1536 920 startup_stm32f103xe.o 154 32 0 9 0 6279 stm32f1xx_hal.o 272 22 0 0 0 28702 stm32f1xx_hal_cortex.o 424 10 0 0 0 1215 stm32f1xx_hal_dma.o 844 40 0 0 0 2664 stm32f1xx_hal_gpio.o 1708 84 0 0 0 4336 stm32f1xx_hal_rcc.o 796 6 0 0 0 6287 stm32f1xx_hal_uart.o 32 0 0 0 0 3762 stm32f1xx_it.o 102 0 0 0 0 699 sys.o 2 0 24 4 0 1295 system_stm32f1xx.o 176 28 0 7 264 3541 usart.o ---------------------------------------------------------------------- 4950 282 362 32 1800 515069 Object Totals 0 0 32 0 0 0 (incl. Generated) 10 0 2 4 0 0 (incl. Padding) ---------------------------------------------------------------------- Code (inc. data) RO Data RW Data ZI Data Debug Library Member Name 8 0 0 0 0 68 __main.o 0 0 0 0 0 0 __rtentry.o 12 0 0 0 0 0 __rtentry2.o 6 0 0 0 0 0 __rtentry4.o 52 8 0 0 0 0 __scatter.o 26 0 0 0 0 0 __scatter_copy.o 28 0 0 0 0 0 __scatter_zi.o 18 0 0 0 0 80 exit.o 6 0 0 0 0 152 heapauxi.o 2 0 0 0 0 0 libinit.o 2 0 0 0 0 0 libinit2.o 2 0 0 0 0 0 libshutdown.o 2 0 0 0 0 0 libshutdown2.o 8 4 0 0 96 68 libspace.o 78 0 0 0 0 80 rt_memclr_w.o 2 0 0 0 0 0 rtexit.o 10 0 0 0 0 0 rtexit2.o 74 0 0 0 0 80 sys_stackheap_outer.o 2 0 0 0 0 68 use_no_semi.o 2 0 0 0 0 68 use_no_semi_2.o ---------------------------------------------------------------------- 344 12 0 0 96 664 Library Totals 4 0 0 0 0 0 (incl. Padding)最后来说一下文章开头提到的项目映射文件的底部项目整体的RO Size、RW Size和ROM Size。RO Size是非易失存储器中保存只读数据的大小由Code段和RO段组成。RW Size是RAM中保存全局数据的大小由RW段和ZI段组成。这不包括函数内部定义的局部变量它们保存在寄存器或者堆栈中。ROM Size是非易失存储器的最小大小由Code段、RO段和RW段组成。
RELATED

相关推荐

Verilog基础:层次化标识符的使用

Verilog基础:层次化标识符的使用

相关阅读 Verilog基础https://blog.csdn.net/weixin_45791458/category_12263729.html?spm1001.2014.3001.5482 一、前言 Verilog HDL中的标识符(identifier)是一个为了引用而给一个Verilog对象起的名字,分为两大类:普通标识符大类和层次化标识符大类。…

📅 2026/10/27 1:16:17
C#海康热成像测温:从温度矩阵到发射率标定的完整实战

C#海康热成像测温:从温度矩阵到发射率标定的完整实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/27 1:11:17
480W开关电源设计:PFC+LLC架构选型、参数计算与调试实战

480W开关电源设计:PFC+LLC架构选型、参数计算与调试实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/27 1:11:17
MORE NEWS

更多资讯

📰

别让错题本变成抄题本:我给孩子用的 AI 错题本开源了

错题本最容易完成的一步,是把题目抄进去。最容易掉链子的一步,是过几天再拿出来,确认孩子真的会做了。 题干要抄,图要画,答案要整理;好不容易收拾干净,下次复习又得翻半天。要是同一道题再次做…

📰

酒店客房WiFi覆盖方案怎么做?勘测、布点与验收判据

客房 WiFi 做得好不好,验收时不是看信号格数,而是看点位复测的数值和高峰期是否仍然可用。很多项目入住以后才发现问题,根子都在第一阶段:没做勘测就按经验布点,墙还没砌完就定了 AP 数量。 一、第一步:勘测…

📰

当 Agent 运行时跑上手机:白泽的移动端双路径设计

白泽是一个旁挂在业务旁、用 Go 写成的单进程 Agent 运行时,把大模型、工具、老系统接口和人工卡点收口成可审计的运行。服务端跑稳后,移动端没有简单做一个手机版网页,而是提供两条路径:一条用 Capacitor 壳遥控远端完整操作台&a…

📰

失控、操纵、侵私:人工智能业务的现实风险

上一篇,我们讨论了人工智能自身的技术缺陷,包括模型幻觉、提示词注入、数据投毒,以及算法、数据和运行环境等环节可能存在的安全隐患。但AI安全问题并不会止步于技术本身。当人工智能进入真实业务场景后,可能产生哪些具体危害&…

📰

PurrPurr AI项圈拆解:499元硬件+年订阅,宠物情绪价值的续费生意能跑通吗

【摘要】以PurrPurr AI宠物项圈为核心样本,覆盖27种行为识别标签、3档订阅定价、3阶段留存验证模型,拆解宠物智能硬件从功能监测转向情绪叙事的创业路径,量化分析硬件毛利与订阅续费的双轮结构,给出4条按时间轴排布的失效边界&…

📰

小白程序员必看:从0理解真正的Agent与大模型背后的工程系统

本文深入剖析了真正的Agent与大模型背后的工程系统,揭示了两者之间的核心差异。文章详细拆解了Agent从接收用户目标到最终执行结果的20步全链路,并介绍了六个关键角色(用户、智能体、技能层、大模型、模型上下文协议、工具)的分工…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬