EDA365电子论坛网
标题:
Cortex-M/R 内核启动过程 / 程序启动流程之启动实例分析
[打印本页]
作者:
uperrua
时间:
2020-11-23 11:17
标题:
Cortex-M/R 内核启动过程 / 程序启动流程之启动实例分析
& d# n3 M$ `4 Z; l
启动实例分析
4 D2 X6 o4 p \8 p' i4 U& \3 y! {/ T
下面我们以STM32F407VG片子为例,看看其调试时的汇编代码(Keil5中)。直接进调试模式,注意:最好将汇编窗口右键改为assembly mode。
5 Y8 \) |; Q4 A6 M
5 h$ g9 S+ R O) N
2.png
(71.99 KB, 下载次数: 2)
下载附件
保存到相册
2020-11-23 11:16 上传
* R2 p3 J1 q, A: b$ }: P' a
首先看看定义的中断向量表部分,如下图:
/ y2 B$ _) n! R# _( g* w; _
; ]+ Q4 K4 |& B. l$ @. U
1.png
(94.14 KB, 下载次数: 3)
下载附件
保存到相册
2020-11-23 11:16 上传
) `, }$ Q" I- [% q1 i
: p9 S% N3 l2 J1 I8 R
其中,SystemInit为 ST 提供的时钟初始化函数(如果使用了外部RAM,可能还包含外部RAM的配置)。接着,就会有如下汇编代码(具体看里面的注释即可):
6 Z% P9 c$ O1 i- p
0 ?. ^4 N$ M6 b/ }
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()函数。
; 执行完后,R10和R11就被赋给成了下面两个值,Map文件中的symbol:
; Region$$Table$$Base 0x08000898 Number 0 anon$$obj.o(Region$$Table)
; Region$$Table$$Limit 0x080008b8 Number 0 anon$$obj.o(Region$$Table)
; !!!-----------注意:以下注释中括号中的数据为我在调试时的值,自行调试时值可能有变化-----------!!!
; !!!-----------注意:以下注释中非括号中的数据一般为左侧地址或者立即数-----------!!!
__scatterload:
0x08000190 A00A ADR r0,{pc}+0x2C ; 将基于PC相对偏移的地址值(0x080001BC)读取到寄存器r0中。
0x08000192 E8900C00 LDM r0,{r10-r11} ; 将R0对应地址存放的的2个字copy到R10~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 ; 比较r10和r11。实际做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个双字copy到R0~R3中,!表示执行语句后将地址赋值给r10。r10 = r10 + 4*4 = 0x08000898 + 0x10 = 0x080008A8.
; R0:表示的是程序加载视图的RW区的起始地址(0x080008B8)
; R1:要复制到的运行域地址(RAM中0x20000000)
; 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,SUBS中S表示把进位结果写入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个双字copy到R0~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) ; 跳转到C的main函数
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
0 W, h% M/ _8 E J. A; V% G# m
* ?7 M2 O# v0 K; m0 K2 B9 c+ Q, ]" @
/ T5 _$ W6 G: R* ?
7 D$ V) u. e$ \3 ~. K5 N6 O
2 n u* g6 G: h/ s+ J
, q( k3 m" o X. _& L" z n
作者:
SsaaM7
时间:
2020-11-23 13:14
Cortex-M/R 内核启动过程 / 程序启动流程之启动实例分析
欢迎光临 EDA365电子论坛网 (https://bbs.eda365.com/)
Powered by Discuz! X3.2