剖析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
,而在啟動函數中只對相應地址值進行了賦值,並未有更復雜的處理。