你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32F1系列之复制data段和清除BSS段(ZI段)

[复制链接]
STMCU小助手 发布时间:2022-8-27 13:29
一、什么是BSS段(ZI段)
bss段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。
bss是英文Block Started by Symbol的简称。
bss段属于静态内存分配。

而在Keil里,BSS段被称为ZI段

二、为什么要复制data段
这是因为对于在STM32F103这类资源紧缺的单片机芯片中,数据段只是暂时先保存在Flash上,在使用前被复制到内存里,而复制到内存这个过程是需要我们自己实现的。实际上在keil中,*(InRoot$$Sections)这一段就是keil帮我们做好的一段代码,当我们调用main函数时,keil会帮我们自动添加。但是为了学习,我们来自己实现一下,那么就需要知道数据段的加载地址(在Flash上的位置)和链接地址(需要放在内存中的位置),在keil中获取这些地址的方法如下:

  1. 数据段的加载地址:        Load$RW_IRAM1$Base
  2. 数据段的链接地址:        Image$RW_IRAM1$Base
  3. 数据段的长度:                 Image$RW_IRAM1$Length
  4. ZI段的链接地址:                Image$RW_IRAM1$ZI$Base
  5. ZI段的长度:                 Image$RW_IRAM1$ZI$Length
复制代码

三、编写代码实现
将start.s修改为如下所示

  1. Stack_Size      EQU     0x00000500                                  ;定义堆栈大小为1024byte
  2.                                 AREA    STACK, NOINIT, READWRITE, ALIGN=3  ;定义一个数据段,标记为STACK,即栈,不写入初始值初,对RAM来说,即初始化为0,8字节对齐
  3. Stack_Mem                SPACE        Stack_Size                                    ;保留Stack_Size大小的栈空间
  4. __initial_sp                                                                                  ;标号,代表堆栈顶部地址,后面有用

  5.                 PRESERVE8                                                        ;指示编译器8字节对齐
  6.                 THUMB                                                                ;指示编译器以后的指令为THUMB指令                                                               


  7. ; Vector Table Mapped to Address 0 at Reset
  8.                                 AREA    RESET, CODE, READONLY                ;定义只读数据段,标记为RESET,其实放在CODE区,位于0地址
  9.                                 EXPORT  __Vectors                                        ;在程序中声明一个全局的标号__Vectors,该标号可在其他的文件中引用
  10.                                        
  11. __Vectors       DCD     __initial_sp                                ;当前地址写入一个字(32bit)数据,值应该为栈顶地址
  12.                 DCD     Reset_Handler                      ;当前地址写入一个字(32bit)数据,值为Reset_Handler指向的地址值,即程序入口地址

  13.                                 AREA    |.text|, CODE, READONLY                ;定义代码段,标记为.text

  14. ; Reset handler        ;利用PROC、ENDP这一对伪指令把程序段分为若干个过程,使程序的结构加清晰
  15. Reset_Handler   PROC                                                                ;过程的开始
  16.                                 EXPORT  Reset_Handler        [WEAK]                ;[WEAK] 弱定义,意思是如果在别处也定义该标号(函数),在链接时用别处的地址。
  17.                                        
  18.                                 IMPORT |Image$RW_IRAM1$Base|                ;从别处导入data段的链接地址
  19.                                 IMPORT |Image$RW_IRAM1$Length|        ;从别处导入data段的长度
  20.                                 IMPORT |Load$RW_IRAM1$Base|                ;从别处导入data段的加载地址
  21.                                 IMPORT |Image$RW_IRAM1$ZI$Base|        ;从别处导入ZI段的链接地址
  22.                                 IMPORT |Image$RW_IRAM1$ZI$Length|;从别处导入ZI段的长度

  23. ; 复制数据段
  24.                                 LDR R0, = |Load$RW_IRAM1$Base|           ;将data段的加载地址存入R0寄存器
  25.                                 LDR R1, = |Image$RW_IRAM1$Base|   ;将data段的链接地址存入R1寄存器
  26.                                 LDR R2, = |Image$RW_IRAM1$Length| ;将data段的长度存入R2寄存器
  27. CopyData               
  28.                                 SUB R2, R2, #4                                                ;每次复制4个字节的data段数据
  29.                                 LDR R3, [R0, R2]                                        ;把加载地址处的值取出到R3寄存器
  30.                                 STR R3, [R1, R2]                                        ;把取出的值从R3寄存器存入到链接地址                                       
  31.                                 CMP R2, #0                                                        ;将计数和0相比较
  32.                                 BNE CopyData                                                ;如果不相等,跳转到CopyData标签处,相等则往下执行

  33. ; 清除BSS段
  34.                                 LDR R0, = |Image$RW_IRAM1$ZI$Base|   ;将bss段的链接地址存入R1寄存器
  35.                                 LDR R1, = |Image$RW_IRAM1$ZI$Length| ;将bss段的长度存入R2寄存器
  36. CleanBss        
  37.                                 SUB R1, R1, #4                                                ;每次清除4个字节的bss段数据
  38.                                 MOV R3, #0                                                        ;将0存入r3寄存器
  39.                                 STR R3, [R0, R1]                                        ;把R3寄存器存入到链接地址                                       
  40.                                 CMP R1, #0                                                        ;将计数和0相比较
  41.                                 BNE CleanBss                                                ;如果不相等,跳转到CleanBss标签处,相等则往下执行
  42.                                 
  43.                                 
  44.                                 IMPORT  mymain                                                ;通知编译器要使用的标号在其他文件
  45.                                 BL                mymain                                                 ;跳转去执行main函数
  46.                                 B                .                                                        ;原地跳转,即处于循环状态
  47.                                 ENDP

  48.                 ALIGN                                                                 ;填充字节使地址对齐
  49.                 END                                                                        ;整个汇编文件结束
复制代码

四、验证
其他文件不做修改,编译烧录运行,可以看到所有变量的值都正确了

20210124143838385.png

五、注意
我们之前看过编译出来的hex文件,发现myzero和my变量也存在,这就意味着这两个本该在bss段的变量也会在Flash中,这就很奇怪了,而事实是:

对于keil来说,一个本该放到BSS段的变量,如果它所占据的空间小于等于8字节自己,keil仍然会把它放在data段里。只有当它所占据的空间大于8字节时,才会放到BSS段。

那么我们将myzero修改为一个数组
20210124144421174.png

这样查看hex文件,可以看到,只有my变量存在了

20210124144510149.png


收藏 评论0 发布时间:2022-8-27 13:29

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版