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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM