技术逻辑代码分析:
/* start address for the initialization values of the .data section.
defined in linker script */
.word _sidata
/ start address for the .data section. defined in linker script /
.word _sdata
/ end address for the .data section. defined in linker script /
.word _edata
/ start address for the .bss section. defined in linker script /
.word _sbss
/ end address for the .bss section. defined in linker script /
.word _ebss
/ stack used for SystemInit_ExtMemCtl; always internal RAM used /
复制
.word表示了在当前位置放一个word型的值,可以理解为一个变量或者数据定义,这个变量同样对对.ld(连接文件)可见。
可以看到定义的变量包括_sidata;_sdata;_edata;_sbss;_ebss,分别用于表示带初始化值的.data段起始地址,.data段的起始地址,结束地址,.bss段的起始地址,结束地址。注释中SystemInit_ExtMemCtl表示配置外部RAM
启动跳转
继续往下看:
/**
- @brief This is the code that gets called when the processor first
- starts execution following a reset event. Only the absolutely
- necessary set is performed, after which the application
- supplied main() routine is called.
- @param None
- @retval : None
*/
.section .text.Reset_Handler
.weak Reset_Handler
.type Reset_Handler, %function
Reset_Handler:
ldr sp, =_estack / set stack pointer /
/ Copy the data segment initializers from flash to SRAM /
movs r1, #0
b LoopCopyDataInit
CopyDataInit:
ldr r3, =_sidata
ldr r3, [r3, r1]
str r3, [r0, r1]
adds r1, r1, #4
LoopCopyDataInit:
ldr r0, =_sdata
ldr r3, =_edata
adds r2, r0, r1
cmp r2, r3
bcc CopyDataInit
ldr r2, =_sbss
b LoopFillZerobss
/ Zero fill the bss segment. /
FillZerobss:
movs r3, #0
str r3, [r2], #4
LoopFillZerobss:
ldr r3, = _ebss
cmp r2, r3
bcc FillZerobss
/ Call the clock system intitialization function./
bl SystemInit
/ Call static constructors /
bl __libc_init_array
/ Call the application's entry point./
bl main
bx lr
.size Reset_Handler, .-Reset_Handler
复制
逐一解释:
开头注释表明:这部分代码在芯片第一次启动或复位后,需要执行的一些必要的操作,在此之后启动main()函数执行
.weak Reset_Handler该伪指令在符号名称的逗号分隔列表上设置弱属性。 如果符号不存在,将创建它们。(弱定义,如果有其他强定义则用强定义替代),即当我们定义一个Reset_Handler函数时,这部分将不起作用
.type Reset_Handler, %function(ELF格式下隐含的标识一个段的开始)此伪指令用于设置符号的类型。%function表示符号是函数名
后面就是汇编函数的定义了,一步步看:
Reset_Handler:LDR指令用于从内存中将一个32位的字读取到指令中的目标寄存器中,即将_estack栈底赋值给SP,SP寄存器是指的是堆栈指针寄存器,将R1寄存器赋值为0,B指令跳转至CopyDataInit函数,通过函数名可以看出,这里是对数据进行初始化。
LoopCopyDataInit:将_sdata赋值给R0,将_edata赋值给R3,将R0和R1的相加结果给R2,注意R1这里是0,即flash的0起始位置?比较R2与R3,如果R2>=R3,则bcc指令执行,进入CopyDataInit函数,否则则将R2置为_sbss并跳转至LoopFillZerobss,之后跳转至SystemInit函数和__libc_init_array中,多说一句__libc_init_array指用了C++代码,所以需要__libc_init_array 来初始化一些东西, 在C++中,全局变量和静态变量的构造函数需要在main函数执行前执行,这些构造函数会放在init_array表中,__libc_init_array函数有调用这些函数的代码
跳转main函数,当main函数执行退出后执行BX LR跳转回LR寄存器,这时候就从main函数跳出来了。
.size Reset_Handler, .-Reset_Handler(ELF格式下隐含标识一个段的结束)该指令设置与符号名称关联的大小。字节大小由可使用标签算术的表达式计算得出。 该伪指令通常用于设置功能符号的大小。