基于STM32看Cortex-M内核相关的一些底层知识

固件起始地址存储了主栈指针和向量表内容

《ARM Cortex-M3与Cortex-M4权威指南》中的4.8章节复位和复位流程中有下面这段的描述:
在复位后以及处理器开始执行程序前,Cortex-M处理器会从存储器中读出头两个字,如图4.30所示。向量表位于存储器的开头部分,它的头两个字为主栈指针(MSP)的初始值,以及代表复位处理起始地址的复位向量(参考本书图4.26和4.5.3节)。处理器读出这两个字后,就会将这些数值赋给MSP和程序计数器(PC)
在这里插入图片描述
当异常时间产生且被处理器内核接受后,响应的异常处理就会执行。要确定异常处理的起始地址,处理器利用了一种向量表机制。向量表为系统存储器内的字数据数组,每个元素都代表一个异常类型的起始地址,如图4.26所示。
在这里插入图片描述
《Cortex-M3处理器技术参考手册》中5.9复位章节中的表5-7显示了复位的行为:
在这里插入图片描述
基于上述描述我们可以知道固件的起始地址存储了主栈指针的初始值,后续存储了向量表的内容。

MAP文件
固件文件
从上面的map文件中我们可以看出程序的栈顶地址就是0x200069b0,从下面的固件中我们可以看出起始地址存放的就是栈顶指针的值。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
基于map文件找出后续程序地址对应的数据内容,和上面向量表对应的内容也完全一致
在这里插入图片描述
细心的你可以能已经发现了,这里固件中存储的向量表的地址和map文件中对应的函数地址不完全一致,差了1,这是因为向量表的LSB位必须置1以表示Thumb状态(Cortex-M处理器不支持ARM状态)
《ARM Cortex-M3与Cortex-M4权威指南》7.5章节:
在这里插入图片描述
启动代码使用的向量表还包含主栈指针(MSP)的初始值,这种设计是很有必要的,因为NMI等异常可能会紧接着复位产生,而此时还没有进行任何初始化操作。

总之,芯片上电后处理器会将第一个数据赋值给SP,第二个数据加载到PC寄存器中,这是由处理器设计决定的。

启动文件分析

启动文件主要做了以下工作:

  1. 初始化栈指针 MSP= _initial_sp
  2. 初始化PC指针 PC=Reset_Handler
  3. 初始化中断向量表
  4. 配置系统时钟
  5. 调用C库函数__main初始化用户堆栈,从而最终调用main函数

复位函数是系统上电后第一个执行的程序。

Code,RO Data,RW Data, ZI Data

map文件中镜像组件大小信息:
在这里插入图片描述

Code : 代码段
RO Data : 只读数据段
RW Data : 读写数据段,定的时候被初始化的变量
ZI Data:未初始化的数据段

在这里插入图片描述

Cortex-M芯片启动详细过程

下图为芯片启动后程序的基本执行流程图:
请添加图片描述
下图为芯片启动后程序执行的详细流程:
请添加图片描述

在这里插入图片描述
Rest_Handler函数是芯片上电后第一个执行的程序。然后会调用C库函数__main()通过分散加载复制函数将加载域中的RW Data复制到执行域,通过分散加载零初始化函数在RAM中开辟出一段空间并初始化为0(该函数实际初始化为0的数据空间包括ZI Data段、Heap段和Stack段)然后初始化用户堆栈和C库并跳转到用户main函数中。

在这里插入图片描述

Regin$$Table

程序在编译链接的时候会生成此分散加载表,在程序执行的过程中会通过C库函数根据该表的信息将flash中的RW Data复制到SRAM中,并在SRAM中开辟出一段空间并初始化为0用于ZI Data、Heap、Stack数据段。
map文件中的Regin$$Table的位置如下:
在这里插入图片描述
对应固件中的地址位置的数据如下:
在这里插入图片描述

描述
08030500RW Data在加载域中的起始位置
20000000RW Data复制到执行域中的起始位置
00000478需要复制RW Data数据的长度
080257A分散加载复制函数的入口地址
080305E8RW Data在加载域中的结束位置
20000478ZI Data在执行域中的起始位置
00006538ZI 数据段的大小(这里包含了ZI Data Heap Stack的总大小)
0802F73A分散加载ZI段初始化函数的入口地址

在这里插入图片描述
在这里插入图片描述
这里 0x6538 + 0x478 = 0x69b0, 0x20000000 + 0x69b0 = 0x200069b0刚好对应于栈顶位置
在这里插入图片描述

进一步固件分析

从上一章节中我们可以知道RW Data的大小为0x478字节,如果所有的这些数据全部直接从固件中复制的话固件的结束位置应为0x08030500+0x478=0x08030978的位置,但实际并不是这样,下图展示了固件实际的结束位置:0x080305E8
在这里插入图片描述
根据MAP文件中的固件大小信息部分我们可以看到,RW Data的大小为232(0xE8)字节,这刚好和固件的大小相对应。
在这里插入图片描述
上面内容说明了RW Data段的数据也不是简单的直接从flash空间直接复制到RAM空间的。实际0xE8的空间存储了RW Data变量的初始值信息,如果初始值一样占用的是同一个初始值空间。在程序运行时在RAM中为RW Data段开辟出0x478的空间,并将初始值赋值给对应的变量。这样的设计可以减小生成固件的大小。

升华

  1. 当你深入向下发掘时,科学的神秘面纱便会一层一层褪去,渐渐露出真容。
  2. 芯片严格遵循着人们创造它的规则在运行,其中有着非常严谨的逻辑。

参考链接

  1. https://m.toutiao.com/is/i2KJkchJ/
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值