嵌入式系统与单片机|技术阅读
登录|注册

您现在的位置是:嵌入式系统与单片机 > 技术阅读 > 嵌入式软件面试之启动文件中data段和bss段代码拷贝分析

嵌入式软件面试之启动文件中data段和bss段代码拷贝分析

引用网上的问题:

"单片机上电初始化后,RAM存储初始化全局变量,这些全局变量是从调试器烧进去的S19文件中获取的吗?" 这是个很好的问题, 全局变量和静态变量的初始化值是保存在Flash中的Const段里的 ,新建一个工程的时候默认有个startup的汇编程序文件,它负责将const段中的初始值付给这些全部变量。这些事情是发生在你的main函数之前的。

这个问题其实简单讲就是:单片机程序下载好之后,所有的数据都存放在flash中,那么map文件中的.data段和.bss段怎么在上电之后放到RAM中呢?

mcu启动后,程序运行需要的data段、bss段在mcu startup阶段拷贝到ram中。其实就是在启动文件中添加一段拷贝代码,将flash中存放的.data段和.bss段拷贝到RAM,以下是以startup_stm32f103xe.s 为例:

Reset_Handler: //在复位函数中包含拷贝操作
/* Copy the data segment initializers from flash to SRAM */ ldr r0, =_sdata //data在RAM的起始地址 ldr r1, =_edata //data在RAM的结束地址 ldr r2, =_sidata //data段的FLASH存储地址 movs r3, #0 //地址偏移寄存器 b LoopCopyDataInit // 跳转到子函数
CopyDataInit: // copy代码 ldr r4, [r2, r3] //将flash中偏移地址是r3的数据拷贝到R4 str r4, [r0, r3] //将R4的数据放到RAM上去 adds r3, r3, #4 // 偏移地址加
LoopCopyDataInit: // 循环拷贝函数 adds r4, r0, r3 //R4的地址是搬到ram的地址 cmp r4, r1 // 比较是否到结束地址,到结束地址的话就表示数据搬完了 bcc CopyDataInit //没有结束的话跳转到copy代码 /* Zero fill the bss segment. */ ldr r2, =_sbss // bss的起始地址 ldr r4, =_ebss //bss的结束地址 movs r3, #0 // 这是初始化的值,0 b LoopFillZerobss //跳转到子函数
FillZerobss: str r3, [r2] //将R2地址初始化为0 adds r2, r2, #4 // 地址加4
LoopFillZerobss: //循环函数 cmp r2, r4 //判断地址是否到结束地址 bcc FillZerobss //没有结束的话跳转到FillZerobss


Keil中是没有这段代码的,应该是放在了KEIl的STM支持包中,如果是自己使用ARM-GCC构建STM32的编译环境,则启动文件中需要加上这段代码。

上述代码每行有添加了注释,说明了功能。有嵌入式er可能会问:这其中的地址标记符是在哪里定义的?像_sdata,_edata,_sidata这些,这些是在链接脚本中的指定好的,此启动代码对应的链接脚本文件中的定义如下:

/* used by the startup to initialize data */ _sidata = LOADADDR(.data);
/* Initialized data sections goes into RAM, load LMA copy after code */ .data : { . = ALIGN(4); _sdata = .; /* create a global symbol at data start */ *(.data) /* .data sections */ *(.data*) /* .data* sections */
. = ALIGN(4); _edata = .; /* define a global symbol at data end */ } >RAM AT> FLASH
/* Uninitialized data section */ . = ALIGN(4); .bss : { /* This is used by the startup in order to initialize the .bss secion */ _sbss = .; /* define a global symbol at bss start */ __bss_start__ = _sbss; *(.bss) *(.bss*) *(COMMON)
. = ALIGN(4); _ebss = .; /* define a global symbol at bss end */ __bss_end__ = _ebss; } >RAM