本文主要是介绍RT-1052学习笔记(2)-Cortex-M内核启动文件_main分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
这篇文章梳理了RT1052的启动过程
从Reset_Handler直至main
- 问题:分析RT1052启动流程的时候,卡在分散加载文件在启动的时候到底是怎么调用的。结果把问题点盯在启动文件的_main函数中。
- 可能自己比较菜吧,死活找不到这函数的定义。没办法,分析试着分析一下map文件。起码map文件中有一些链接信息
__Vectors_End 0x60002400 Data 0 startup_mimxrt1052.o(RESET)__main 0x60002401 Thumb Code 0 entry.o(.ARM.Collect$$$$00000000)_main_stk 0x60002401 Thumb Code 0 entry4.o(.ARM.Collect$$$$00000003)_main_scatterload 0x60002405 Thumb Code 0 entry5.o(.ARM.Collect$$$$00000004)__main_after_scatterload 0x60002409 Thumb Code 0 entry5.o(.ARM.Collect$$$$00000004)_main_clock 0x60002409 Thumb Code 0 entry7b.o(.ARM.Collect$$$$00000008)_main_cpp_init 0x60002409 Thumb Code 0 entry8b.o(.ARM.Collect$$$$0000000A)_main_init 0x60002409 Thumb Code 0 entry9a.o(.ARM.Collect$$$$0000000B)__rt_final_cpp 0x60002411 Thumb Code 0 entry10a.o(.ARM.Collect$$$$0000000D)__rt_final_exit 0x60002411 Thumb Code 0 entry11a.o(.ARM.Collect$$$$0000000F)Reset_Handler 0x60002415 Thumb Code 24 startup_mimxrt1052.o(.text)
- 然后,向量表结束到中断向量函数弱定义代码之间就是_main的代码链接信息了。
- 但是!entry.o(.ARM.Collect$$$$00000000)这是什么鬼?
- ARM.Collect?按字面意思猜测猜测:会不会是自动生成的东西?
- 那到底是编译生成的还是链接生成的?
- 先从_main功能入手一下下。
- _main函数网上的说法是准备C运行环境,然后跳转到真正的main函数中执行代码
- 既然是准备C运行环境,初始化RW段总是需要吧?RW段的运行时域写在分散加载文件中,那东西是在链接的时候才会用到。所以,上面那一堆entry*.o文件应该是在链接程序的时候调用的了
- 找一下MDK的帮助文档,找到一段话。文档在C:\Keil_v5\ARM\Hlp\DUI0377G_02_mdk_armlink_user_guide.pdf
- 大意就是说链接程序时加入--startup=_main选项,MDK在链接程序的时候看到就会自动创建_main。
- 然后知道了_main是怎么生成的了。现在单步跟踪一下MDK到底生成了什么样的_main。
- 再次分析:看到所有的entryxx.o都是__main函数调用的子函数所在的文件,各子函数分别负责不同的功能。不是所有函数都会被编译进去,不需要的函数会被去掉。比如本程序中只保留_main_scatterload函数用作RW段的重定位
__Vectors_End 0x60002400 Data 0 startup_mimxrt1052.o(RESET)__main 0x60002401 Thumb Code 0 entry.o(.ARM.Collect$$$$00000000)_main_stk 0x60002401 Thumb Code 0 entry4.o(.ARM.Collect$$$$00000003)_main_scatterload 0x60002405 Thumb Code 0 entry5.o(.ARM.Collect$$$$00000004)__main_after_scatterload 0x60002409 Thumb Code 0 entry5.o(.ARM.Collect$$$$00000004)_main_clock 0x60002409 Thumb Code 0 entry7b.o(.ARM.Collect$$$$00000008)_main_cpp_init 0x60002409 Thumb Code 0 entry8b.o(.ARM.Collect$$$$0000000A)_main_init 0x60002409 Thumb Code 0 entry9a.o(.ARM.Collect$$$$0000000B)__rt_final_cpp 0x60002411 Thumb Code 0 entry10a.o(.ARM.Collect$$$$0000000D)__rt_final_exit 0x60002411 Thumb Code 0 entry11a.o(.ARM.Collect$$$$0000000F)Reset_Handler 0x60002415 Thumb Code 24 startup_mimxrt1052.o(.text)
_main入口:
直接就进入了_main_scatterload函数,_main_stk被跳过不执行了。
_main_scatterload函数
- 首先就是加载0x60005068到r4
- 再就是加载0x60005088到r5
这两个数据是干嘛的?看map文件,这部分存放的就是程序链接的时候存放在flash的RW段数据。这段汇编的作用就是初始化RW段和ZI段数据。
Region$$Table$$Base 0x60005068 Number 0 anon$$obj.o(Region$$Table)Region$$Table$$Limit 0x60005088 Number 0 anon$$obj.o(Region$$Table)
0x60005068 | 0x60005088 | 散列加载文件信息结束地址 |
0x60005069 | 0x20000000 | RW段运行时域起始地址 |
0x60005070 | 0x0000001C | RW段大小 |
0x60005074 | 0x60004ca0 | __scatterload_copy入口地址 |
0x60005078 | 0x600050a4 | 不知道什么东西 |
0x6000507c | 0x2000001c | ZI段运行时域起始地址 |
0x60005080 | 0x00000024 | ZI段大小 |
0x60005084 | 0x60004cb0 | __scatterload_null入口地址 |
搞定之后就真的跳转到熟悉的main函数了
其实在链接的时候还有很多和函数生成,不过在现在没有被用到就不在分析。道理都一样,以后就大致跟着流程走一遍就可以捋清了
重新梳理一遍启动文件执行流程
- 放上代码
Reset_Handler PROCEXPORT Reset_Handler [WEAK]IMPORT SystemInitIMPORT __mainCPSID I ; Mask interruptsLDR R0, =0xE000ED08 ;0xE000ED08 VTOR RW -b Vector Table Offset Register,摘自CM7参考手册;告诉CM7当异常发生时去哪里找异常向量入口(异常向量入口重定向)LDR R1, =__Vectors ;异常向量首地址;__Vectors指向的数据为-> DCD |Image$$ARM_LIB_STACK$$ZI$$Limit|;即从分散加载文件中连接计算出来的栈顶地址STR R1, [R0] ;将r1寄存器的值传送到地址值为r0的(存储器)内存LDR R2, [R1] ;将存储器地址为R1的字数据读入寄存器R2。MSR MSP, R2 ;设置栈顶LDR R0, =SystemInit BLX R0 ;跳转SystemInit函数CPSIE i ; Unmask interruptsLDR R0, =__mainBX R0ENDP
- 上电系统进入boot ROM,经过初始化,判断启动设置后进入Reset_Handler
- 屏蔽中断
- 设置CM7异常向量表入口
- 设置栈顶
- 跳转SystemInit:初始化浮点运算单元,关闭看门狗,关闭Systick时钟,设置ICACHE,DCACHE
这个函数想再分析一波,想一下,程序执行到这里的时候并没有初始化什么C语言的准备环境,比如RW段初始化,ZI段初始化。仅仅是初始化了栈顶。为什么这个函数可以正常运行?
答:是位置无关码,这个函数并没有定义什么已经初始化的变量,没有调用全局变量,没有静态变量。所有操作都是设置寄存器。所以这个函数并不依赖RW+ZI段。所以这个函数可以正常运行。
怎么利用SystemInit函数?
答:可以在这个函数中加入初始化外扩的SDRAM,然后把需要放在SDRAM的段通过分散加载文件进行配置。等_main函数执行的时候就可以实现RW+ZI段的初始化了
- 跳转_main:具体动作上面分析了
- 进入真正main函数
这篇关于RT-1052学习笔记(2)-Cortex-M内核启动文件_main分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!