剖析startup_stm32f407xx.s文件
剖析startup_stm32f407xx.s文件
感谢gcc编译环境下ARM汇编语法(伪指令)提供的相关ARM伪指令功能的介绍,本文据此详细介绍STM32F407芯片所使用的startup_stm32f407xx.s
文件
文件头注释
文件开头是关于文件的描述,先粘过来后面解释:
/**
******************************************************************************
* @file startup_stm32f407xx.s
* @author MCD Application Team
* @brief STM32F407xx Devices vector table for GCC based toolchains.
* This module performs:
* - Set the initial SP
* - Set the initial PC == Reset_Handler,
* - Set the vector table entries with the exceptions ISR address
* - Branches to main in the C library (which eventually
* calls main()).
* After Reset the Cortex-M4 processor is in Thread mode,
* priority is Privileged, and the Stack is set to Main.
******************************************************************************
* @attention
*
* <h2><center>© COPYRIGHT 2017 STMicroelectronics</center></h2>
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
开头部分描述了文件的用途及版权声明:基于GCC编译链的STM32F407xx设备中断向量表,主要描述了
- 初始SP,PC寄存器的初始值。
- PC的初始值即
Reset_Handler
- 设置中断向量表入口地址,并用异常地址初始化向量表。 向量表里面保存的是异常响应的时候服务例程的入口地址。STM32把向量表放在0地址开始的code区。
- 转到C库的
__main
(最后调用mian()) - 复位CortexM4之后,处理器处于线程模式,特权优先级。
定义
继续往下看
.syntax unified
.cpu cortex-m4
.fpu softvfp
.thumb
.global g_pfnVectors
.global Default_Handler
.syntax unified
是一个指示,默认值divided(分裂的) 旧样式,下面的指令使用ARM和THUMB各自独立的语法。unified (统一的)新样式,下面的指令使用ARM和THUMB通用格式。.cpu
表示后面用到的CPU平台为cortex-M4.fpu
表示后面使用的是软浮点,软浮点即Soft-float,浮点单元即VFP,(vector floating-point),相关资料可据此查询.thumb
使用thumb模式等价于.code 16;gcc -mthumb
.global
定义了全局符号(symbol),.global
使该符号对.ld
(连接文件)可见。g_pfnVectors
即中断向量表,Default_Handler
我们这里先不解释,后面再看
继续往下看:
/* 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格式下隐含标识一个段的结束)该指令设置与符号名称关联的大小。字节大小由可使用标签算术的表达式计算得出。 该伪指令通常用于设置功能符号的大小。
默认中断服务函数
继续往下看
/**
* @brief This is the code that gets called when the processor receives an
* unexpected interrupt. This simply enters an infinite loop, preserving
* the system state for examination by a debugger.
* @param None
* @retval None
*/
.section .text.Default_Handler,"ax",%progbits
Default_Handler:
Infinite_Loop:
b Infinite_Loop
.size Default_Handler, .-Default_Handler
- 注释说明如果处理器收到一个未预料的中断,将会进入这个死循环中,即
Default_Handler
.section .text.Reset_Handler
这里表示定义的是.text段中的Reset_Handler
段,ax表示权限,ax是 allocation execute的缩写,表示该节区可分配并且可执行,progbits是type,详细定义为.section section_name [, “flags”[, %type[,flag_specific_arguments]]]
这里不具体解释。
中断向量表和服务函数
这部分主要是中断向量表的定义,摘抄部分如下:
/******************************************************************************
*
* The minimal vector table for a Cortex M3. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
*******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
.word HardFault_Handler
/*省略*/
/* External Interrupts */
.word WWDG_IRQHandler /* Window WatchDog */
.word PVD_IRQHandler /* PVD through EXTI Line detection */
.word TAMP_STAMP_IRQHandler /* Tamper and TimeStamps through the EXTI line */
.word RTC_WKUP_IRQHandler /* RTC Wakeup through the EXTI line */
.word FLASH_IRQHandler /* FLASH */
.word RCC_IRQHandler /* RCC */
/*省略*/
/*******************************************************************************
*
* Provide weak aliases for each Exception handler to the Default_Handler.
* As they are weak aliases, any function with the same name will override
* this definition.
*
*******************************************************************************/
.weak NMI_Handler
.thumb_set NMI_Handler,Default_Handler
.weak HardFault_Handler
.thumb_set HardFault_Handler,Default_Handler
/*省略*/
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
- 注释部分,表明中断向量表需要在物理地址0x00000000的位置上,如果是IAP当然可以通过程序后续配置调整地址大小,但是第一次启动必然要从0开始
.section .isr_vector,"a",%progbits
定义中断向量段和它的类型,a表示可分配,%progbits
表示段内包含数据。.type g_pfnVectors, %object
段符号名为g_pfnVectors
,%object表示符号为数据对象。.size g_pfnVectors, .-g_pfnVectors
表示g_pfnVectors
的大小是从当前位置-定义位置。.word _estack
在当前位置放置一个word型的值,这个值为_estack;后面同理。.thumb_set NMI_Handler,Default_Handler
等效于.set指令,因为它创建了一个符号,该符号是另一个符号的别名(可能尚未定义)。 该指令还具有添加的属性,因为它以.thumb_func指令相同的方式将别名符号标记为thumb函数入口点。即NMI_Handler
默认用Default_Handler
替代,但同时NMI_Handler
还是个若引用,因此当我们在程序里定义了这个中断服务函数的时候,就会替代这里。
总结
以上即整个.S文件的全部解析,总结一下即定义了中断向量表及相关DATA段,BSS段的地址位置定义。之后定义了启动函数(类似__main
)和默认中断函数Default_Handler
,而在启动函数中只对相应地址值进行了赋值,并未有更复杂的处理。