技术逻辑代码分析:
代码语言:javascript复制/* 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
启动跳转
继续往下看:
代码语言:javascript复制/**
* @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格式下隐含标识一个段的结束)该指令设置与符号名称关联的大小。字节大小由可使用标签算术的表达式计算得出。 该伪指令通常用于设置功能符号的大小。