ARM之Cortex M3的启动过程

一、简介

ARM Cortex-M内核的复位启动过程也被称为复位序列(Reset sequence)。ARM Cortex-M内核的复位启动过程与其他大部分CPU不同,也与之前的ARM架构(ARM920T、ARM7TDMI等)不相同。大部分CPU复位后都是从0x00000000处取得第一条指令开始运行的,然而在ARM Cortex-M内核中并不是这样的。其复位序列为:

  1. 从地址0x0000_0000处取出MSP的初始值;
  2. 从地址0x0000_0004处取出PC的初始值,然后从这个值对应的地址处取指。事实上,地址0x00000004开始存放的就是默认中断向量表

ARM之Cortex M3的启动过程

ARM Cortex-M内核的中断向量表布局情况如下图所示:

ARM之Cortex M3的启动过程

注意:中断向量表的位置可以改变,此处是默认情况下的设置。

在ARM Cortex-M内核中,发生异常后,并不是去执行中断向量表中对应位置处的代码,而是将对应位置处的数据存入PC中,然后去此地址处进行取指。简而言之,在ARM Cortex-M的中断向量表中不应该放置跳转指令,而是该放置ISR程序的入口地址。另外还有两个细节问题需要注意:

  1. 0x00000000处存放的MSP初始值最低三位需要是0;
  2. 0x00000004处存放的地址最低位必须是1。

第一个问题是因为在ARM上编程,但凡涉及到调用,就需要遵循一套规约AAPCS——《Procedure Call Standard for the ARM Architecture》。AAPCS中对栈使用的约定是这样的:

5.2.1.1

Universal stack constraints

At all times the following basic constraints must hold:

Stack-limit < SP <= stack-base. The stack pointer must lie within the extent of the stack.

SP mod 4 = 0. The stack must at all times be aligned to a word boundary.

5.2.1.2

Stack constraints at a public interface

The stack must also conform to the following constraint at a public interface:

SP mod 8 = 0. The stack must be double-word aligned.

简而言之,规约规定,栈任何时候都必须4字节对齐,在调用入口需8字节对齐,而且SP的最低两位在硬件上就被置为0了。

第二个问题与ARM模式与Thumb模式有关。ARM中PC中的地址必须是32位对齐的,其最低两位也被硬件上置0了,故写入PC中的数据最低两位并不代表真实的取址地址。ARM中使用最低一位来判断这条指令是ARM指令还是Thumb指令,若最低位为0,代表ARM指令;若最低位为1,代表Thumb指令。在Cortex-M内核中,并不支持ARM模式,若强行切换到ARM模式会引发一个Hard Fault。

二、启动文件

目前,多数MCU厂商都提供一个启动文件。当然,编程者也可以自己编写启动文件,具体编写要求ARM的网站上都有相关文档进行说明。下面分析一下STM32启动文件startup_stm32f407xx.s,具体看里面的注释。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447

 

;******************** (C) COPYRIGHT 2017 STMicroelectronics ********************
;* File Name          : startup_stm32f407xx.s
;* Author             : MCD Application Team
;* Version            : V2.6.1
;* Date               : 14-February-2017
;* Description        : STM32F407xx devices vector table for MDK-ARM toolchain. 
;*                      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 CortexM4 processor is in Thread mode,
;*                      priority is Privileged, and the Stack is set to Main.
;* <<< Use Configuration Wizard in Context Menu >>>   
;*******************************************************************************

;* 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.

;*******************************************************************************

; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
;   <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Stack_Size      EQU     0x0800                                  
定义栈大小
                ; AREA 
命令指示汇编器汇编一个新的代码段或数据段。 
                AREA    STACK, NOINIT, READWRITE, ALIGN=3       
代码段名称为STACK,未初始化,允许读写,8字节对齐
Stack_Mem       SPACE   Stack_Size                              
分配Stack_Size的栈空间,首地址赋给Stack_Mem
__initial_sp                                                    
栈顶指针,全局变量


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>

Heap_Size      EQU     0x200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base                                                     
堆末底部地址
Heap_Mem        SPACE   Heap_Size
__heap_limit                                                    
堆界限地址

                PRESERVE8                                       
指定当前文件保持堆栈八字节对齐
                THUMB                                           ; Thumb
命令模式


; Vector Table Mapped to Address 0 at Reset                     ; 
终端向量表 重启时程序从这里运行,必须将该地址映射到0x00000000
                AREA    RESET, DATA, READONLY                   
代码段名称为RESETDATA类型,只读
                EXPORT  __Vectors                               
导出中断向量表地址(供外部可以使用)
                EXPORT  __Vectors_End                           
导出中断向量表结束指针(供外部可以使用)
                EXPORT  __Vectors_Size                          
中断向量表大小(供外部可以使用)
__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler
                DCD     HardFault_Handler          ; Hard Fault Handler
                DCD     MemManage_Handler          ; MPU Fault Handler
                DCD     BusFault_Handler           ; Bus Fault Handler
                DCD     UsageFault_Handler         ; Usage Fault Handler
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     0                          ; Reserved
                DCD     SVC_Handler                ; SVCall Handler
                DCD     DebugMon_Handler           ; Debug Monitor Handler
                DCD     0                          ; Reserved
                DCD     PendSV_Handler             ; PendSV Handler
                DCD     SysTick_Handler            ; SysTick Handler

                ; External Interrupts
                DCD     WWDG_IRQHandler                   ; Window WatchDog                                        
                DCD     PVD_IRQHandler                    ; PVD through EXTI Line detection                        
                DCD     TAMP_STAMP_IRQHandler             ; Tamper and TimeStamps through the EXTI line            
                DCD     RTC_WKUP_IRQHandler               ; RTC Wakeup through the EXTI line                       
                DCD     FLASH_IRQHandler                  ; FLASH                                           
                DCD     RCC_IRQHandler                    ; RCC                                             
                DCD     EXTI0_IRQHandler                  ; EXTI Line0                                             
                DCD     EXTI1_IRQHandler                  ; EXTI Line1                                             
                DCD     EXTI2_IRQHandler                  ; EXTI Line2                                             
                DCD     EXTI3_IRQHandler                  ; EXTI Line3                                             
                DCD     EXTI4_IRQHandler                  ; EXTI Line4                                             
                DCD     DMA1_Stream0_IRQHandler           ; DMA1 Stream 0                                   
                DCD     DMA1_Stream1_IRQHandler           ; DMA1 Stream 1                                   
                DCD     DMA1_Stream2_IRQHandler           ; DMA1 Stream 2                                   
                DCD     DMA1_Stream3_IRQHandler           ; DMA1 Stream 3                                   
                DCD     DMA1_Stream4_IRQHandler           ; DMA1 Stream 4                                   
                DCD     DMA1_Stream5_IRQHandler           ; DMA1 Stream 5                                   
                DCD     DMA1_Stream6_IRQHandler           ; DMA1 Stream 6                                   
                DCD     ADC_IRQHandler                    ; ADC1, ADC2 and ADC3s                            
                DCD     CAN1_TX_IRQHandler                ; CAN1 TX                                                
                DCD     CAN1_RX0_IRQHandler               ; CAN1 RX0                                               
                DCD     CAN1_RX1_IRQHandler               ; CAN1 RX1                                               
                DCD     CAN1_SCE_IRQHandler               ; CAN1 SCE                                               
                DCD     EXTI9_5_IRQHandler                ; External Line[9:5]s                                    
                DCD     TIM1_BRK_TIM9_IRQHandler          ; TIM1 Break and TIM9                   
                DCD     TIM1_UP_TIM10_IRQHandler          ; TIM1 Update and TIM10                 
                DCD     TIM1_TRG_COM_TIM11_IRQHandler     ; TIM1 Trigger and Commutation and TIM11
                DCD     TIM1_CC_IRQHandler                ; TIM1 Capture Compare                                   
                DCD     TIM2_IRQHandler                   ; TIM2                                            
                DCD     TIM3_IRQHandler                   ; TIM3                                            
                DCD     TIM4_IRQHandler                   ; TIM4                                            
                DCD     I2C1_EV_IRQHandler                ; I2C1 Event                                             
                DCD     I2C1_ER_IRQHandler                ; I2C1 Error                                             
                DCD     I2C2_EV_IRQHandler                ; I2C2 Event                                             
                DCD     I2C2_ER_IRQHandler                ; I2C2 Error                                               
                DCD     SPI1_IRQHandler                   ; SPI1                                            
                DCD     SPI2_IRQHandler                   ; SPI2                                            
                DCD     USART1_IRQHandler                 ; USART1                                          
                DCD     USART2_IRQHandler                 ; USART2                                          
                DCD     USART3_IRQHandler                 ; USART3                                          
                DCD     EXTI15_10_IRQHandler              ; External Line[15:10]s                                  
                DCD     RTC_Alarm_IRQHandler              ; RTC Alarm (A and B) through EXTI Line                  
                DCD     OTG_FS_WKUP_IRQHandler            ; USB OTG FS Wakeup through EXTI line                        
                DCD     TIM8_BRK_TIM12_IRQHandler         ; TIM8 Break and TIM12                  
                DCD     TIM8_UP_TIM13_IRQHandler          ; TIM8 Update and TIM13                 
                DCD     TIM8_TRG_COM_TIM14_IRQHandler     ; TIM8 Trigger and Commutation and TIM14
                DCD     TIM8_CC_IRQHandler                ; TIM8 Capture Compare                                   
                DCD     DMA1_Stream7_IRQHandler           ; DMA1 Stream7                                           
                DCD     FMC_IRQHandler                    ; FMC                                             
                DCD     SDIO_IRQHandler                   ; SDIO                                            
                DCD     TIM5_IRQHandler                   ; TIM5                                            
                DCD     SPI3_IRQHandler                   ; SPI3                                            
                DCD     UART4_IRQHandler                  ; UART4                                           
                DCD     UART5_IRQHandler                  ; UART5                                           
                DCD     TIM6_DAC_IRQHandler               ; TIM6 and DAC1&2 underrun errors                   
                DCD     TIM7_IRQHandler                   ; TIM7                   
                DCD     DMA2_Stream0_IRQHandler           ; DMA2 Stream 0                                   
                DCD     DMA2_Stream1_IRQHandler           ; DMA2 Stream 1                                   
                DCD     DMA2_Stream2_IRQHandler           ; DMA2 Stream 2                                   
                DCD     DMA2_Stream3_IRQHandler           ; DMA2 Stream 3                                   
                DCD     DMA2_Stream4_IRQHandler           ; DMA2 Stream 4                                   
                DCD     ETH_IRQHandler                    ; Ethernet                                        
                DCD     ETH_WKUP_IRQHandler               ; Ethernet Wakeup through EXTI line                      
                DCD     CAN2_TX_IRQHandler                ; CAN2 TX                                                
                DCD     CAN2_RX0_IRQHandler               ; CAN2 RX0                                               
                DCD     CAN2_RX1_IRQHandler               ; CAN2 RX1                                               
                DCD     CAN2_SCE_IRQHandler               ; CAN2 SCE                                               
                DCD     OTG_FS_IRQHandler                 ; USB OTG FS                                      
                DCD     DMA2_Stream5_IRQHandler           ; DMA2 Stream 5                                   
                DCD     DMA2_Stream6_IRQHandler           ; DMA2 Stream 6                                   
                DCD     DMA2_Stream7_IRQHandler           ; DMA2 Stream 7                                   
                DCD     USART6_IRQHandler                 ; USART6                                           
                DCD     I2C3_EV_IRQHandler                ; I2C3 event                                             
                DCD     I2C3_ER_IRQHandler                ; I2C3 error                                             
                DCD     OTG_HS_EP1_OUT_IRQHandler         ; USB OTG HS End Point 1 Out                      
                DCD     OTG_HS_EP1_IN_IRQHandler          ; USB OTG HS End Point 1 In                       
                DCD     OTG_HS_WKUP_IRQHandler            ; USB OTG HS Wakeup through EXTI                         
                DCD     OTG_HS_IRQHandler                 ; USB OTG HS                                      
                DCD     DCMI_IRQHandler                   ; DCMI  
                DCD     0                                 ; Reserved                                              
                DCD     HASH_RNG_IRQHandler               ; Hash and Rng
                DCD     FPU_IRQHandler                    ; FPU
                
                                         
__Vectors_End

__Vectors_Size  EQU  __Vectors_End - __Vectors              
计算中断向量表的大小

                AREA    |.text|, CODE, READONLY             
代码段,|.text| 用于表示由 C 编译程序产生的代码段,或用于以某种方式与 C 库关联的代码段。 CODE类型,只读
以下开始定义各种中断,第一个便是复位中断,顺序与上面的终端向量表一致!
; Reset handler
Reset_Handler    PROC                                       
代码开始,与ENDP成对出现    
                 EXPORT  Reset_Handler             [WEAK]   
复位中断,[WEAK]修饰代表其他文件有函数定义优先调用
        IMPORT  SystemInit                                  
导入外部函数SystemInit
        IMPORT  __main                                      
导入外部函数__main

                 LDR     R0, =SystemInit
                 BLX     R0                                 
无返回调用SystemInit
                 LDR     R0, =__main
                 BX      R0                                 
有返回调用__main
                 ENDP                                       
代码结束,与PROC成对出现

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP
HardFault_Handler\
                PROC
                EXPORT  HardFault_Handler          [WEAK]
                B       .
                ENDP
MemManage_Handler\
                PROC
                EXPORT  MemManage_Handler          [WEAK]
                B       .
                ENDP
BusFault_Handler\
                PROC
                EXPORT  BusFault_Handler           [WEAK]
                B       .
                ENDP
UsageFault_Handler\
                PROC
                EXPORT  UsageFault_Handler         [WEAK]
                B       .
                ENDP
SVC_Handler     PROC
                EXPORT  SVC_Handler                [WEAK]
                B       .
                ENDP
DebugMon_Handler\
                PROC
                EXPORT  DebugMon_Handler           [WEAK]
                B       .
                ENDP
PendSV_Handler  PROC
                EXPORT  PendSV_Handler             [WEAK]
                B       .
                ENDP
SysTick_Handler PROC
                EXPORT  SysTick_Handler            [WEAK]
                B       .
                ENDP
终端向量表的External Interrupts部分。 默认的外部中断,通常有外部实现。先导出各种符号以供外部使用,然后时默认的定义
Default_Handler PROC

                EXPORT  WWDG_IRQHandler                   [WEAK]                                        
                EXPORT  PVD_IRQHandler                    [WEAK]                      
                EXPORT  TAMP_STAMP_IRQHandler             [WEAK]         
                EXPORT  RTC_WKUP_IRQHandler               [WEAK]                     
                EXPORT  FLASH_IRQHandler                  [WEAK]                                         
                EXPORT  RCC_IRQHandler                    [WEAK]                                            
                EXPORT  EXTI0_IRQHandler                  [WEAK]                                            
                EXPORT  EXTI1_IRQHandler                  [WEAK]                                             
                EXPORT  EXTI2_IRQHandler                  [WEAK]                                            
                EXPORT  EXTI3_IRQHandler                  [WEAK]                                           
                EXPORT  EXTI4_IRQHandler                  [WEAK]                                            
                EXPORT  DMA1_Stream0_IRQHandler           [WEAK]                                
                EXPORT  DMA1_Stream1_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream2_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream3_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream4_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream5_IRQHandler           [WEAK]                                   
                EXPORT  DMA1_Stream6_IRQHandler           [WEAK]                                   
                EXPORT  ADC_IRQHandler                    [WEAK]                         
                EXPORT  CAN1_TX_IRQHandler                [WEAK]                                                
                EXPORT  CAN1_RX0_IRQHandler               [WEAK]                                               
                EXPORT  CAN1_RX1_IRQHandler               [WEAK]                                                
                EXPORT  CAN1_SCE_IRQHandler               [WEAK]                                                
                EXPORT  EXTI9_5_IRQHandler                [WEAK]                                    
                EXPORT  TIM1_BRK_TIM9_IRQHandler          [WEAK]                  
                EXPORT  TIM1_UP_TIM10_IRQHandler          [WEAK]                
                EXPORT  TIM1_TRG_COM_TIM11_IRQHandler     [WEAK] 
                EXPORT  TIM1_CC_IRQHandler                [WEAK]                                   
                EXPORT  TIM2_IRQHandler                   [WEAK]                                            
                EXPORT  TIM3_IRQHandler                   [WEAK]                                            
                EXPORT  TIM4_IRQHandler                   [WEAK]                                            
                EXPORT  I2C1_EV_IRQHandler                [WEAK]                                             
                EXPORT  I2C1_ER_IRQHandler                [WEAK]                                             
                EXPORT  I2C2_EV_IRQHandler                [WEAK]                                            
                EXPORT  I2C2_ER_IRQHandler                [WEAK]                                               
                EXPORT  SPI1_IRQHandler                   [WEAK]                                           
                EXPORT  SPI2_IRQHandler                   [WEAK]                                            
                EXPORT  USART1_IRQHandler                 [WEAK]                                          
                EXPORT  USART2_IRQHandler                 [WEAK]                                          
                EXPORT  USART3_IRQHandler                 [WEAK]                                         
                EXPORT  EXTI15_10_IRQHandler              [WEAK]                                  
                EXPORT  RTC_Alarm_IRQHandler              [WEAK]                  
                EXPORT  OTG_FS_WKUP_IRQHandler            [WEAK]                        
                EXPORT  TIM8_BRK_TIM12_IRQHandler         [WEAK]                 
                EXPORT  TIM8_UP_TIM13_IRQHandler          [WEAK]                 
                EXPORT  TIM8_TRG_COM_TIM14_IRQHandler     [WEAK] 
                EXPORT  TIM8_CC_IRQHandler                [WEAK]                                   
                EXPORT  DMA1_Stream7_IRQHandler           [WEAK]                                          
                EXPORT  FMC_IRQHandler                    [WEAK]                                             
                EXPORT  SDIO_IRQHandler                   [WEAK]                                             
                EXPORT  TIM5_IRQHandler                   [WEAK]                                             
                EXPORT  SPI3_IRQHandler                   [WEAK]                                             
                EXPORT  UART4_IRQHandler                  [WEAK]                                            
                EXPORT  UART5_IRQHandler                  [WEAK]                                            
                EXPORT  TIM6_DAC_IRQHandler               [WEAK]                   
                EXPORT  TIM7_IRQHandler                   [WEAK]                    
                EXPORT  DMA2_Stream0_IRQHandler           [WEAK]                                  
                EXPORT  DMA2_Stream1_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream2_IRQHandler           [WEAK]                                    
                EXPORT  DMA2_Stream3_IRQHandler           [WEAK]                                    
                EXPORT  DMA2_Stream4_IRQHandler           [WEAK]                                 
                EXPORT  ETH_IRQHandler                    [WEAK]                                         
                EXPORT  ETH_WKUP_IRQHandler               [WEAK]                     
                EXPORT  CAN2_TX_IRQHandler                [WEAK]                                               
                EXPORT  CAN2_RX0_IRQHandler               [WEAK]                                               
                EXPORT  CAN2_RX1_IRQHandler               [WEAK]                                               
                EXPORT  CAN2_SCE_IRQHandler               [WEAK]                                               
                EXPORT  OTG_FS_IRQHandler                 [WEAK]                                       
                EXPORT  DMA2_Stream5_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream6_IRQHandler           [WEAK]                                   
                EXPORT  DMA2_Stream7_IRQHandler           [WEAK]                                   
                EXPORT  USART6_IRQHandler                 [WEAK]                                           
                EXPORT  I2C3_EV_IRQHandler                [WEAK]                                              
                EXPORT  I2C3_ER_IRQHandler                [WEAK]                                              
                EXPORT  OTG_HS_EP1_OUT_IRQHandler         [WEAK]                      
                EXPORT  OTG_HS_EP1_IN_IRQHandler          [WEAK]                      
                EXPORT  OTG_HS_WKUP_IRQHandler            [WEAK]                        
                EXPORT  OTG_HS_IRQHandler                 [WEAK]                                      
                EXPORT  DCMI_IRQHandler                   [WEAK]                                                                                 
                EXPORT  HASH_RNG_IRQHandler               [WEAK]
                EXPORT  FPU_IRQHandler                    [WEAK]
                
WWDG_IRQHandler                                                       
PVD_IRQHandler                                      
TAMP_STAMP_IRQHandler                  
RTC_WKUP_IRQHandler                                
FLASH_IRQHandler                                                       
RCC_IRQHandler                                                            
EXTI0_IRQHandler                                                          
EXTI1_IRQHandler                                                           
EXTI2_IRQHandler                                                          
EXTI3_IRQHandler                                                         
EXTI4_IRQHandler                                                          
DMA1_Stream0_IRQHandler                                       
DMA1_Stream1_IRQHandler                                          
DMA1_Stream2_IRQHandler                                          
DMA1_Stream3_IRQHandler                                          
DMA1_Stream4_IRQHandler                                          
DMA1_Stream5_IRQHandler                                          
DMA1_Stream6_IRQHandler                                          
ADC_IRQHandler                                         
CAN1_TX_IRQHandler                                                            
CAN1_RX0_IRQHandler                                                          
CAN1_RX1_IRQHandler                                                           
CAN1_SCE_IRQHandler                                                           
EXTI9_5_IRQHandler                                                
TIM1_BRK_TIM9_IRQHandler                        
TIM1_UP_TIM10_IRQHandler                      
TIM1_TRG_COM_TIM11_IRQHandler  
TIM1_CC_IRQHandler                                               
TIM2_IRQHandler                                                           
TIM3_IRQHandler                                                           
TIM4_IRQHandler                                                           
I2C1_EV_IRQHandler                                                         
I2C1_ER_IRQHandler                                                         
I2C2_EV_IRQHandler                                                        
I2C2_ER_IRQHandler                                                           
SPI1_IRQHandler                                                          
SPI2_IRQHandler                                                           
USART1_IRQHandler                                                       
USART2_IRQHandler                                                       
USART3_IRQHandler                                                      
EXTI15_10_IRQHandler                                            
RTC_Alarm_IRQHandler                            
OTG_FS_WKUP_IRQHandler                                
TIM8_BRK_TIM12_IRQHandler                      
TIM8_UP_TIM13_IRQHandler                       
TIM8_TRG_COM_TIM14_IRQHandler  
TIM8_CC_IRQHandler                                               
DMA1_Stream7_IRQHandler                                                 
FMC_IRQHandler                                                            
SDIO_IRQHandler                                                            
TIM5_IRQHandler                                                            
SPI3_IRQHandler                                                            
UART4_IRQHandler                                                          
UART5_IRQHandler                                                          
TIM6_DAC_IRQHandler                            
TIM7_IRQHandler                              
DMA2_Stream0_IRQHandler                                         
DMA2_Stream1_IRQHandler                                          
DMA2_Stream2_IRQHandler                                           
DMA2_Stream3_IRQHandler                                           
DMA2_Stream4_IRQHandler                                        
ETH_IRQHandler                                                         
ETH_WKUP_IRQHandler                                
CAN2_TX_IRQHandler                                                           
CAN2_RX0_IRQHandler                                                          
CAN2_RX1_IRQHandler                                                          
CAN2_SCE_IRQHandler                                                          
OTG_FS_IRQHandler                                                    
DMA2_Stream5_IRQHandler                                          
DMA2_Stream6_IRQHandler                                          
DMA2_Stream7_IRQHandler                                          
USART6_IRQHandler                                                        
I2C3_EV_IRQHandler                                                          
I2C3_ER_IRQHandler                                                          
OTG_HS_EP1_OUT_IRQHandler                           
OTG_HS_EP1_IN_IRQHandler                            
OTG_HS_WKUP_IRQHandler                                
OTG_HS_IRQHandler                                                   
DCMI_IRQHandler                                                                                                             
HASH_RNG_IRQHandler
FPU_IRQHandler  
           
                B       .

                ENDP

                ALIGN

;*******************************************************************************
; User Stack and Heap initialization    
编译器预处理命令,主要是用来初始化用户堆栈
;*******************************************************************************
                 IF      :DEF:__MICROLIB    ; "DEF"
的用法为 :DEF:X 就是说X定义了则为真,否则为假。若定义了__MICROLIB,则将__initial_sp__heap_base__heap_limit亦即栈顶地址,堆始末地址赋予全局属性,使外部程序可以使用。
                
                 EXPORT  __initial_sp
                 EXPORT  __heap_base
                 EXPORT  __heap_limit
                
                 ELSE                       
如果没定义__MICROLIB,则使用默认的C运行时库
                
                 IMPORT  __use_two_region_memory        
用于指定存储器模式为双段模式,即一部分储存区用于栈空间,其他的存储区用于堆空间,堆区空间可以为0,但是,这样就不能调用malloc()内存分配函数;堆区空间也可以由存储器分配,也可以从执行环境中继承。在汇编代码中,通过 IMPORT __use_two_region_memory 表明使用双段模式;在C语言中,通过 #pragma import(__use_two_region_memory)语句表明使用双段模式。
                 EXPORT  __user_initial_stackheap
                 
__user_initial_stackheap                    
此处是初始化两区的堆栈空间,堆是从由低到高的增长,栈是由高向低生长的,两个是互相独立的数据段,并不能交叉使用。

                 LDR     R0, =  Heap_Mem                        
保存堆始地址
                 LDR     R1, =(Stack_Mem + Stack_Size)          
保存栈的大小
                 LDR     R2, = (Heap_Mem +  Heap_Size)          
保存堆的大小
                 LDR     R3, = Stack_Mem                        
保存栈顶指针
                 BX      LR

                 ALIGN                                          
填充字节使地址对齐

                 ENDIF

                 END                                            ; END 
命令指示汇编器,已到达一个源文件的末尾。

;************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE*****

 

接下来,看看实际程序运行图如下

ARM之Cortex M3的启动过程

其中,SystemInit为ST提供的时钟初始化函数(如果使用了外部RAM,可能还包含外部RAM的配置)

三、系统函数(__main)

ARM自己的编译套件提供了如下三种库(如果使用的是IAR或者GNU则可能有区别

ARM之Cortex M3的启动过程

以下分析,均是基于Cstandardlib来说的,并不是适用于其他两种库。

嵌入式应用程序在调用用户定义的main()函数之前,需要一个被称为"初始化序列"的流程。如下图:

ARM之Cortex M3的启动过程

这个初始化序列程序被称为startup code 或者boot code。对于ARM编译套件,这些代码就在ARM编译套件的库中。下面我们以STM32F407VG片子为例,看看其调试时的汇编代码(Keil5中)。直接进调试模式,注意:最好将汇编窗口右键改为assembly mode

ARM之Cortex M3的启动过程

接着,就会有如下汇编代码:

0x08000180 0243 DCW 0x0243       ; 小端模式,地址:0x08000243

0x08000182 0800 DCW 0x0800

0x08000184 0243 DCW 0x0243       ; 小端模式,地址:0x08000243

0x08000186 0800 DCW 0x0800                                   

; 从此网上即为中断向量表,与上一节的启动文件中的中断向量表相对应,32位地址,小端模式

; 与初始化序列相同,

__main:

0x08000188 F000F802 BL.W __scatterload (0x08000190)       ; 负责把RW/RO输出段从装载域地址复制到运行域地址,并完成了ZI运行域的初始化工作。

0x0800018C F000F83C BL.W __rt_entry (0x08000208)          ; 负责初始化堆、栈,完成C库函数的初始化。其会调用一系列初始化函数,最后自动跳转向main()函数。

 

; 执行完后,R10R11就被赋给成了下面两个值,Map文件中的symbol

;       Region

TableTable
Table)

; !!!-----------注意:以**释中括号中的数据为我在调试时的值,自行调试时值可能有变化-----------!!!

; !!!-----------注意:以**释中非括号中的数据一般为左侧地址或者立即数-----------!!!

__scatterload:

0x08000190 A00A ADR r0,{pc}+0x2C     ; 将基于PC相对偏移的地址值(0x080001BC)读取到寄存器r0中。

0x08000192 E8900C00 LDM r0,{r10-r11}     ; R0对应地址存放的的2个字copyR10~R11中。即:r10 = 0x000006DC; r11 = 0x000006FC

0x08000196 4482 ADD r10,r10,r0       ; r10 = r10 + r0 = 0x000006DC + 0x080001BC = 0x08000898

0x08000198 4483 ADD r11,r11,r0       ; r11 = r11 + r0 = 0x000006FC + 0x080001BC = 0x080008B8

0x0800019A F1AA0701 SUB r7,r10,#0x01     ; r7 = r10 - 0x01 = 0x08000898 - 0x01 = 0x08000897

__scatterload_null:

0x0800019E 45DA CMP r10,r11          ; 比较r10r11。实际做r10-r11操作,根据结果修改CPSR中条件标志位的值

0x080001A0 D101 BNE 0x080001A6       ; Z 标志位不等于零时, 跳转到0x080001A6

0x080001A2 F000F831 BL.W __rt_entry (0x08000208)  ; 最后一步:在执行完__scatterload_copy__scatterload_zeroinit后,r10 == r11 ,上面的跳转不成立,执行该句

0x080001A6 F2AF0E09 ADR.W lr,{pc}-0x07     ; 将基于PC相对偏移的地址值(0x0800019F)读取到寄存器lr中。lr = 0x0800019F

0x080001AA E8BA000F LDM r10!,{r0-r3}     ; R10对应地址存放的的4个双字copyR0~R3,!表示执行语句后将地址赋值给r10r10 = r10 + 4*4 = 0x08000898 + 0x10 = 0x080008A8.

                                                    ;       R0:表示的是程序加载视图的RW区的起始地址(0x080008B8

                                                    ;       R1:要复制到的运行域地址(RAM0x20000000

                                                    ;       R2:要复制的RW数据的个数(0x00000020

                                                    ;       R3:__scatterload_copy函数的起始地址0x080001C4

0x080001AE F0130F01 TST r3,#0x01         ;

0x080001B2 BF18 IT NE

0x080001B4 1AFB SUBNE r3,r7,r3

0x080001B6 F0430301 ORR r3,r3,#0x01

0x080001BA 4718 BX r3               ; 跳转到r3,也就是__scatterload_copy函数,开始复制数据

0x080001BC 06DC DCW 0x06DC

0x080001BE 0000 DCW 0x0000

0x080001C0 06FC DCW 0x06FC

0x080001C2 0000 DCW 0x0000

__scatterload_copy:                ; 该函数负责将镜像中的RW数据复制到芯片的ARM

0x080001C4 3A10 SUBS r2,r2,#0x10      ; 循环:R2=R2-0x10,SUBSS表示把进位结果写入CPSR

0x080001C6 BF24 ITT CS

0x080001C8 C878 LDMCS r0!,{r3-r6}

0x080001CA C178 STMCS r1!,{r3-r6}

0x080001CC D8FA BHI __scatterload_copy (0x080001C4)  ; 循环:条件成立跳转到回

0x080001CE 0752 LSLS r2,r2,#29

0x080001D0 BF24 ITT CS

0x080001D2 C830 LDMCS r0!,{r4-r5}

0x080001D4 C130 STMCS r1!,{r4-r5}

0x080001D6 BF44 ITT MI

0x080001D8 6804 LDRMI r4,[r0,#0x00]

0x080001DA 600C STRMI r4,[r1,#0x00]

0x080001DC 4770 BX lr               ; 这里返回到lr = 0x0800019F,即在此调用__scatterload_null。会继续将R10对应地址存放的的4个双字copyR0~R3中,但是,此时的R10由于之前的一次调用,其值已经增加

                                                    ;       R0:是程序加载视图的RW区的起始地址(0x080008D8 = 0x080008B8 + 0x20 上面执行后面的部分)

                                                    ;       R1:是要输出的执行视图的RW区的地址(RAM 0x20000020

                                                    ;       R2:要复制的RW数据的个数(0x00000660

                                                    ;       R3:__scatterload_zeroinit函数的起始地址0x080001E0

                                                    ;       接下来就会跳转到__scatterload_zeroinit

 

0x080001DE 0000 MOVS r0,r0

__scatterload_zeroinit:

0x080001E0 2300 MOVS r3,#0x00

0x080001E2 2400 MOVS r4,#0x00

0x080001E4 2500 MOVS r5,#0x00

0x080001E6 2600 MOVS r6,#0x00

0x080001E8 3A10 SUBS r2,r2,#0x10      ; 循环

0x080001EA BF28 IT CS

0x080001EC C178 STMCS r1!,{r3-r6}

0x080001EE D8FB BHI 0x080001E8       ; 循环:条件成立跳转到回

0x080001F0 0752 LSLS r2,r2,#29

0x080001F2 BF28 IT CS

0x080001F4 C130 STMCS r1!,{r4-r5}

0x080001F6 BF48 IT MI

0x080001F8 600B STRMI r3,[r1,#0x00]

0x080001FA 4770 BX lr               ; 这里返回到lr = 0x0800019F,即在此调用__scatterload_null。这次回去后r10 == r11.回去后会跳转到__rt_entry

__rt_lib_init:

0x080001FC B51F PUSH {r0-r4,lr}

__rt_lib_init_fp_1:

0x080001FE F000FB45 BL.W _fp_init (0x0800088C)

__rt_lib_init_alloca_1:

0x08000202 BD1F POP {r0-r4,pc}

__rt_lib_shutdown:

0x08000204 B510 PUSH {r4,lr}

__rt_lib_shutdown_cpp_1:

0x08000206 BD10 POP {r4,pc}

__rt_entry:                        ; 在执行完__scatterload后,会紧接着执行该函数

0x08000208 F000F831 BL.W __user_setup_stackheap (0x0800026E)  ; 设置堆栈的函数,该函数中会调用由用户实现的__user_initial_stackheap函数,如第二节的启动文件中最后的代码即为用户实现的堆栈初始化该函数

0x0800020C 4611 MOV r1,r2

__rt_entry_li:

0x0800020E F7FFFFF5 BL.W __rt_lib_init (0x080001FC)   ; 初始化C

__rt_entry_main:

0x08000212 F000FA3B BL.W main (0x0800068C)            ; 跳转到Cmain函数

0x08000216 F000F84F BL.W exit (0x080002B8)            ; 如果main返回,则执行该函数,结束程序运行

__rt_exit:

0x0800021A B403 PUSH {r0-r1}

__rt_exit_ls:

0x0800021C F7FFFFF2 BL.W __rt_lib_shutdown (0x08000204)

__rt_exit_exit:

0x08000220 BC03 POP {r0-r1}

0x08000222 F000F857 BL.W _sys_exit (0x080002D4)

0x08000226 0000 MOVS r0,r0

0x08000226 0000 MOVS r0,r0

; 此处往下,就是定义的各个中断向量的实现代码,第一个就是复位中断,程序就是从复位中断开始执行的

Reset_Handler:

0x08000228 4809 LDR r0,[pc,#36] ; @0x08000250

0x0800022A 4780 BLX r0

0x0800022C 4809 LDR r0,[pc,#36] ; @0x08000254

0x0800022E 4700 BX r0

NMI_Handler:

0x08000230 E7FE B NMI_Handler (0x08000230)

HardFault_Handler:

0x08000232 E7FE B HardFault_Handler (0x08000232)

MemManage_Handler:

0x08000234 E7FE B MemManage_Handler (0x08000234)

BusFault_Handler:

0x08000236 E7FE B BusFault_Handler (0x08000236)

UsageFault_Handler:

0x08000238 E7FE B UsageFault_Handler (0x08000238)

SVC_Handler:

0x0800023A E7FE B SVC_Handler (0x0800023A)

DebugMon_Handler:

0x0800023C E7FE B DebugMon_Handler (0x0800023C)

PendSV_Handler:

0x0800023E E7FE B PendSV_Handler (0x0800023E)

SysTick_Handler:

0x08000240 E7FE B SysTick_Handler (0x08000240)

Default_Handler:

0x08000242 E7FE B Default_Handler (0x08000242)

__user_initial_stackheap:

0x08000244 4804 LDR r0,[pc,#16] ; @0x08000258

0x08000246 4905 LDR r1,[pc,#20] ; @0x0800025C

0x08000248 4A05 LDR r2,[pc,#20] ; @0x08000260

0x0800024A 4B06 LDR r3,[pc,#24] ; @0x08000264

0x0800024C 4770 BX lr

0x0800024E 0000 DCW 0x0000

0x08000250 0621 DCW 0x0621

0x08000252 0800 DCW 0x0800

0x08000254 0189 DCW 0x0189

0x08000256 0800 DCW 0x0800

0x08000258 0080 DCW 0x0080

0x0800025A 2000 DCW 0x2000

0x0800025C 0680 DCW 0x0680

0x0800025E 2000 DCW 0x2000

0x08000260 0280 DCW 0x0280

0x08000262 2000 DCW 0x2000

0x08000264 0280 DCW 0x0280

0x08000266 2000 DCW 0x2000

__use_two_region_memory:

0x08000268 4770 BX lr

__rt_heap_escrow$2region:

0x0800026A 4770 BX lr

__rt_heap_expand$2region:

0x0800026C 4770 BX lr

__user_setup_stackheap:

0x0800026E 4675 MOV r5,lr

0x08000270 F000F82C BL.W __user_libspace (0x080002CC)

0x08000274 46AE MOV lr,r5

0x08000276 0005 MOVS r5,r0

0x08000278 4669 MOV r1,sp

0x0800027A 4653 MOV r3,r10

0x0800027C F0200007 BIC r0,r0,#0x07

0x08000280 4685 MOV sp,r0

0x08000282 B018 ADD sp,sp,#0x60

0x08000284 B520 PUSH {r5,lr}

0x08000286 F7FFFFDD BL.W __user_initial_stackheap (0x08000244)

0x0800028A E8BD4020 POP {r5,lr}

0x0800028E F04F0600 MOV r6,#0x00

0x08000292 F04F0700 MOV r7,#0x00

0x08000296 F04F0800 MOV r8,#0x00

0x0800029A F04F0B00 MOV r11,#0x00

0x0800029E F0210107 BIC r1,r1,#0x07

0x080002A2 46AC MOV r12,r5

0x080002A4 E8AC09C0 STM r12!,{r6-r8,r11}

0x080002A8 E8AC09C0 STM r12!,{r6-r8,r11}

0x080002AC E8AC09C0 STM r12!,{r6-r8,r11}

0x080002B0 E8AC09C0 STM r12!,{r6-r8,r11}

0x080002B4 468D MOV sp,r1

0x080002B6 4770 BX lr

exit:

0x080002B8 B510 PUSH {r4,lr}

0x080002BA 4604 MOV r4,r0

0x080002BC F3AF8000 NOP.W

0x080002C0 4620 MOV r0,r4

0x080002C2 E8BD4010 POP {r4,lr}

0x080002C6 F7FFBFA8 B.W __rt_exit (0x0800021A)

0x080002CA 0000 MOVS r0,r0

__user_libspace:

0x080002CC 4800 LDR r0,[pc,#0] ; @0x080002D0

0x080002CE 4770 BX lr

0x080002D0 0020 DCW 0x0020

0x080002D2 2000 DCW 0x2000

_sys_exit:

0x080002D4 4901 LDR r1,[pc,#4] ; @0x080002DC

0x080002D6 2018 MOVS r0,#0x18

0x080002D8 BEAB BKPT 0xAB

0x080002DA E7FE B 0x080002DA

0x080002DC 0026 DCW 0x0026

0x080002DE 0002 DCW 0x0002