RT-1052学习笔记(2)-Cortex-M内核启动文件_main分析

2023-11-23 16:59

本文主要是介绍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函数

  1. 首先就是加载0x60005068到r4
  2. 再就是加载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)
散列加载文件信息
0x600050680x60005088散列加载文件信息结束地址
0x600050690x20000000RW段运行时域起始地址
0x600050700x0000001CRW段大小
0x600050740x60004ca0__scatterload_copy入口地址
0x600050780x600050a4不知道什么东西
0x6000507c0x2000001cZI段运行时域起始地址
0x600050800x00000024ZI段大小
0x600050840x60004cb0__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分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/419408

相关文章

Nexus安装和启动的实现教程

《Nexus安装和启动的实现教程》:本文主要介绍Nexus安装和启动的实现教程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、Nexus下载二、Nexus安装和启动三、关闭Nexus总结一、Nexus下载官方下载链接:DownloadWindows系统根

MyBatis Plus 中 update_time 字段自动填充失效的原因分析及解决方案(最新整理)

《MyBatisPlus中update_time字段自动填充失效的原因分析及解决方案(最新整理)》在使用MyBatisPlus时,通常我们会在数据库表中设置create_time和update... 目录前言一、问题现象二、原因分析三、总结:常见原因与解决方法对照表四、推荐写法前言在使用 MyBATis

Python主动抛出异常的各种用法和场景分析

《Python主动抛出异常的各种用法和场景分析》在Python中,我们不仅可以捕获和处理异常,还可以主动抛出异常,也就是以类的方式自定义错误的类型和提示信息,这在编程中非常有用,下面我将详细解释主动抛... 目录一、为什么要主动抛出异常?二、基本语法:raise关键字基本示例三、raise的多种用法1. 抛

Java中实现线程的创建和启动的方法

《Java中实现线程的创建和启动的方法》在Java中,实现线程的创建和启动是两个不同但紧密相关的概念,理解为什么要启动线程(调用start()方法)而非直接调用run()方法,是掌握多线程编程的关键,... 目录1. 线程的生命周期2. start() vs run() 的本质区别3. 为什么必须通过 st

Go学习记录之runtime包深入解析

《Go学习记录之runtime包深入解析》Go语言runtime包管理运行时环境,涵盖goroutine调度、内存分配、垃圾回收、类型信息等核心功能,:本文主要介绍Go学习记录之runtime包的... 目录前言:一、runtime包内容学习1、作用:① Goroutine和并发控制:② 垃圾回收:③ 栈和

github打不开的问题分析及解决

《github打不开的问题分析及解决》:本文主要介绍github打不开的问题分析及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、找到github.com域名解析的ip地址二、找到github.global.ssl.fastly.net网址解析的ip地址三

Oracle修改端口号之后无法启动的解决方案

《Oracle修改端口号之后无法启动的解决方案》Oracle数据库更改端口后出现监听器无法启动的问题确实较为常见,但并非必然发生,这一问题通常源于​​配置错误或环境冲突​​,而非端口修改本身,以下是系... 目录一、问题根源分析​​​二、保姆级解决方案​​​​步骤1:修正监听器配置文件 (listener.

MySQL版本问题导致项目无法启动问题的解决方案

《MySQL版本问题导致项目无法启动问题的解决方案》本文记录了一次因MySQL版本不一致导致项目启动失败的经历,详细解析了连接错误的原因,并提供了两种解决方案:调整连接字符串禁用SSL或统一MySQL... 目录本地项目启动报错报错原因:解决方案第一个:第二种:容器启动mysql的坑两种修改时区的方法:本地

Mysql的主从同步/复制的原理分析

《Mysql的主从同步/复制的原理分析》:本文主要介绍Mysql的主从同步/复制的原理分析,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录为什么要主从同步?mysql主从同步架构有哪些?Mysql主从复制的原理/整体流程级联复制架构为什么好?Mysql主从复制注意

java -jar命令运行 jar包时运行外部依赖jar包的场景分析

《java-jar命令运行jar包时运行外部依赖jar包的场景分析》:本文主要介绍java-jar命令运行jar包时运行外部依赖jar包的场景分析,本文给大家介绍的非常详细,对大家的学习或工作... 目录Java -jar命令运行 jar包时如何运行外部依赖jar包场景:解决:方法一、启动参数添加: -Xb