查看: 2979|回复: 0

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

[复制链接]
  • TA的每日心情
    开心
    2025-7-11 08:53
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3873

    主题

    7477

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39278
    最后登录
    2025-7-21
    发表于 2020-2-3 13:31:09 | 显示全部楼层 |阅读模式
    RT-1052学习笔记(2)-Cortex-M内核启动文件_main分析




    这篇文章梳理了RT1052的启动过程


    从Reset_Handler直至main


    问题:分析RT1052启动流程的时候,卡在分散加载文件在启动的时候到底是怎么调用的。结果把问题点盯在启动文件的_main函数中。
    可能自己比较菜吧,死活找不到这函数的定义。没办法,分析试着分析一下map文件。起码map文件中有一些链接信息
    1. <font face="微软雅黑" size="3">
    2.     __Vectors_End                            0x60002400   Data           0  startup_mimxrt1052.o(RESET)
    3.     __main                                   0x60002401   Thumb Code     0  entry.o(.ARM.Collect$00000000)
    4.     _main_stk                                0x60002401   Thumb Code     0  entry4.o(.ARM.Collect$00000003)
    5.     _main_scatterload                        0x60002405   Thumb Code     0  entry5.o(.ARM.Collect$00000004)
    6.     __main_after_scatterload                 0x60002409   Thumb Code     0  entry5.o(.ARM.Collect$00000004)
    7.     _main_clock                              0x60002409   Thumb Code     0  entry7b.o(.ARM.Collect$00000008)
    8.     _main_cpp_init                           0x60002409   Thumb Code     0  entry8b.o(.ARM.Collect$0000000A)
    9.     _main_init                               0x60002409   Thumb Code     0  entry9a.o(.ARM.Collect$0000000B)
    10.     __rt_final_cpp                           0x60002411   Thumb Code     0  entry10a.o(.ARM.Collect$0000000D)
    11.     __rt_final_exit                          0x60002411   Thumb Code     0  entry11a.o(.ARM.Collect$0000000F)

    12. </font>
    复制代码
    然后,向量表结束到中断向量函数弱定义代码之间就是_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
    79.png
    大意就是说链接程序时加入--startup=_main选项,MDK在链接程序的时候看到就会自动创建_main。
    然后知道了_main是怎么生成的了。现在单步跟踪一下MDK到底生成了什么样的_main。
    再次分析:看到所有的entryxx.o都是__main函数调用的子函数所在的文件,各子函数分别负责不同的功能。不是所有函数都会被编译进去,不需要的函数会被去掉。比如本程序中只保留_main_scatterload函数用作RW段的重定位
    1. <font face="微软雅黑" size="3">   __Vectors_End                            0x60002400   Data           0  startup_mimxrt1052.o(RESET)
    2.     __main                                   0x60002401   Thumb Code     0  entry.o(.ARM.Collect$00000000)
    3.     _main_stk                                0x60002401   Thumb Code     0  entry4.o(.ARM.Collect$00000003)
    4.     _main_scatterload                        0x60002405   Thumb Code     0  entry5.o(.ARM.Collect$00000004)
    5.     __main_after_scatterload                 0x60002409   Thumb Code     0  entry5.o(.ARM.Collect$00000004)
    6.     _main_clock                              0x60002409   Thumb Code     0  entry7b.o(.ARM.Collect$00000008)
    7.     _main_cpp_init                           0x60002409   Thumb Code     0  entry8b.o(.ARM.Collect$0000000A)
    8.     _main_init                               0x60002409   Thumb Code     0  entry9a.o(.ARM.Collect$0000000B)
    9.     __rt_final_cpp                           0x60002411   Thumb Code     0  entry10a.o(.ARM.Collect$0000000D)
    10.     __rt_final_exit                          0x60002411   Thumb Code     0  entry11a.o(.ARM.Collect$0000000F)


    11. </font>
    复制代码
    80.png
    直接就进入了_main_scatterload函数,_main_stk被跳过不执行了。
    81.png
    1.首先就是加载0x60005068到r4
    2.再就是加载0x60005088到r5
    这两个数据是干嘛的?看map文件,这部分存放的就是程序链接的时候存放在flash的RW段数据。这段汇编的作用就是初始化RW段和ZI段数据。
    82.png
    搞定之后就真的跳转到熟悉的main函数了



    其实在链接的时候还有很多和函数生成,不过在现在没有被用到就不在分析。道理都一样,以后就大致跟着流程走一遍就可以捋清了


    重新梳理一遍启动文件执行流程


    放上代码
    1. <font face="微软雅黑" size="3">
    2. Reset_Handler   PROC
    3.                 EXPORT  Reset_Handler             [WEAK]
    4.                 IMPORT  SystemInit
    5.                 IMPORT  __main

    6.                 CPSID   I               ; Mask interrupts
    7.                 LDR     R0, =0xE000ED08        ;0xE000ED08 VTOR RW -b Vector Table Offset Register,摘自CM7参考手册
    8.                                 ;告诉CM7当异常发生时去哪里找异常向量入口(异常向量入口重定向)
    9.                 LDR     R1, =__Vectors        ;异常向量首地址
    10.                                 ;__Vectors指向的数据为-> DCD     |Image$ARM_LIB_STACK$ZI$Limit|
    11.                                 ;即从分散加载文件中连接计算出来的栈顶地址
    12.                 STR     R1, [R0]                ;将r1寄存器的值传送到地址值为r0的(存储器)内存
    13.                 LDR     R2, [R1]                ;将存储器地址为R1的字数据读入寄存器R2。
    14.                 MSR     MSP, R2                        ;设置栈顶
    15.                 LDR     R0, =SystemInit       
    16.                 BLX     R0                                ;跳转SystemInit函数
    17.                 CPSIE   i               ; Unmask interrupts
    18.                 LDR     R0, =__main
    19.                 BX      R0
    20. <span style="color: rgb(56, 58, 66); white-space: pre; background-color: rgb(250, 250, 250);">ENDP</span></font>
    复制代码
    上电系统进入boot ROM,经过初始化,判断启动设置后进入Reset_Handler
    屏蔽中断
    设置CM7异常向量表入口
    设置栈顶
    跳转SystemInit:初始化浮点运算单元,关闭看门狗,关闭Systick时钟,设置ICACHE,DCACHE
    这个函数想再分析一波,想一下,程序执行到这里的时候并没有初始化什么C语言的准备环境,比如RW段初始化,ZI段初始化。仅仅是初始化了栈顶。为什么这个函数可以正常运行?


    答:是位置无关码,这个函数并没有定义什么已经初始化的变量,没有调用全局变量,没有静态变量。所有操作都是设置寄存器。所以这个函数并不依赖RW+ZI段。所以这个函数可以正常运行。


    怎么利用SystemInit函数?


    答:可以在这个函数中加入初始化外扩的SDRAM,然后把需要放在SDRAM的段通过分散加载文件进行配置。等_main函数执行的时候就可以实现RW+ZI段的初始化了


    跳转_main:具体动作上面分析了
    进入真正main函数


    作者:weixin_42264572         文章出处:点击

    qiandao qiandao
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-22 01:04 , Processed in 0.078525 second(s), 20 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表