为什么要学习汇编代码一(更加深刻理解芯片的启动流程)

背景介绍

本文章探讨的是cortex M 系列的芯片的启动过程,其它的相关的芯片可以进行借鉴。本文所引述的代码位cortex M0相关连的代码,参考的文章是arm官方的原版的文档。
文章转载请标注:https://blog.csdn.net/XG_2013/article/details/107508866

问题引入

笔者是芯片原厂的软件开发的组长,由于长时间和一些运用我们芯片做方案的方案商的开发人员接触,发现做方案的开发人员对汇编代码和芯片本身的理解比较欠缺。由于这些欠缺,可以很明显的看出在解决一些隐晦的bug和代码编写的性能方面显得非常吃力。为什么学习汇编代码是一个小系列,本文以汇编为路线详细阐释芯片的启动的流程。本文推荐阅读的书籍
arm 官方的文档
上述的文档,可以在arm官网获得,也可以通过keil的book获得。

keil books
上图通过keil的开发工具找到的。

芯片启动的reset

芯片复位
上图摘自arm cortex M0的权威指南。
这个过程可以分为2个部分来看:

  1. 取第一条指令之前:这个过程是MCU的硬件逻辑处理的,软件没法干预。
  2. 取第一条指令之后:执行复位的中断函数

执行中断复位函数之前,为什么需要读取MSP的初始值?(硬件的数字逻辑自动完成的)

有些人肯定会说这是明白的事,软件运行肯定要设置主栈指针。这句话我觉得是对的,但是在第一条指令过后还会有设置主栈指针的操作,这会不会意味着硬件读取的MSP的操作不是很有必要呢?我们看下面这张图:
在这里插入图片描述
上图是一个典型的reset的中断复位函数,注意中断向量表和中断复位函数是2个概念。中断向量表放的是函数指针,这些函数指针指向一个个中断复位函数
进入中断复位函数后,执行了一个SystemInit 的函数。汇编原理如下
LDR R0,==SystemInit ,把SystemInit 的函数的地址加载到寄存器R0
BLX R0 跳转到=SystemInit。

SystemInit 是一个用户自己的函数,可以完成一些系统相关的初始化,比如更新系统的工作频率。如果在System Init使用到了栈,比如局部变量的使用。我这儿强调一下,不是所有的函数调用都会用到栈。所以为了整个系统更加具备普适性和完毕性,硬件在复位的时候完成栈的初始化。

__main 函数到底运行了什么东西?

由于__main 是编译器自带的库函数很难找到源码,如果你懂汇编就能很清楚知道这个问题。我们通过fromelf工具获取到汇编文件,参考日下图的文章进行操作。
在这里插入图片描述
这类给一个典型的操作方式,鼓励大家从参考的文档中找到方法,鼓励培养英文的阅读能力。

在这里插入图片描述
我们在看看具体的汇编代码:
在这里插入图片描述
从大的轮廓能看到__main 函数是完成了,主栈指针的初始化,全局变量的初始化(典型的是把RW变量搬到ram,把ZI段在RAM初始为零),然后跳转的main函数,由于这块内容比较多,我着重解析如几点:
1、主栈的指针是存放在0地址,为什么软件读取主栈指针不从0地址读取呢?
在这里插入图片描述
原因:0地址的内容和软件读取的0x364的内容是一样的,为什么这样做还不知道。

2、下图是main函数地址,上图第三步跳转的是0xa92d,实际的main函数是0xa92c。
在这里插入图片描述
原因:thumb 指令需要最低为1,区分thumb 指令和arm 指令,实际执行的时候减一。
在这里插入图片描述

RW ZI RO 字段的细致分析

这个问题懂了就是非常简单,不懂就会很绕。我们很早学习单片机的时候都知道,指令在flash,变量的在ram。但是变量是怎么跑到ram中呢? flash 只有指令么?

flash的下载过程

我们通过keil 编译的bin文件通过jlink 下载到flash,这个过程很容易理解bin 文件和flash 存放的内容一摸一样。
bin 文件 == flash 内容
那bin 文件有那些内容呢:

  1. 代码指令
  2. 常量(RO)
  3. RW 变量(全局变量且初始化)
  4. 其它特殊东西
    是不是很奇怪,为什么bin 文件有全局变量的RW 的内容,我们想想如果斌文件没有RW变量,怎么能够在ram 初始化呢,这意味着我们要在bin文件存放这个rw变量的

RW的变量的搬移过程

在这里插入图片描述
如上图:R2代表变量的个数,R0 代表flash存放的RW变量的位置,R1 代表ram实际变量运行的位置。这一段翻译如下:

for(uint32_t i = 0;i < 变量总数;i++)
	*p_ram_var = *p_flash_var;
	 p_ram_var ++;
	 p_flash_var++

到这RW变量应该非常清楚了吧,bin 文件存放一边,程序运行的时候在__main 函数搬移到ram

ZI 段为什么bin文件不需要存放:

由于ZI段时全局变量初始为0,或者没有初始化。所以bin文件不需要存放,*这不是意味着ram值默认是0。bin 文件只要存放ZI段的大小和ZI段的首地址即可。

在这里插入图片描述
如上图是吧ZI段初始化为0的操作,这个过程大家自己看吧。

在这里插入图片描述
上图是一个MAP文件内容,大家参考一下在反思一下。

进阶的问题探讨

1、是不是RW段一定需要搬移到RAM区?
关注作者,持续更新中。

结论

通过上述的内容,一些比较细致的过程,我们可以通过汇编代码了解的非常细致,纯粹的解释容易遗忘且逻辑性不是很强。

  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

XG_2013

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值