《嵌入式 - 嵌入式大杂烩》Keil反编译入门
Posted Bruceoxl
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《嵌入式 - 嵌入式大杂烩》Keil反编译入门相关的知识,希望对你有一定的参考价值。
在阅读本文之前,你需要有汇编和寄存器的基础知识,请参看笔者以前的文章。
4 反汇编代码全解析
进入debug模式,在View下选择disassembly window。
这样就可将机器码和对应的代码对应起来。当程序运行起来了,也就从异常向量表中跳转到Reset_Handler中,然后跳转到main函数中,而main函数是在栈中,因此需要设置占空间的起始位置。根据STM32的参考手册,SRAM的其起始地址和大小如下:
因此栈顶为起始位置加上栈的大小即可,只要不超过SRAM即可。
值得注意的是,栈是向低地址扩展的数据结构,是一块连续的内存区域,栈顶的地址和栈的最大容量是在通过LDR设置,因此需要根据应用需求合理分配栈空间。
接下来往下走,如果在汇编中不打断点,会默认进入main函数的一条指令,就从这里分析。为了分析方便,这里还有使用上一节方便出来的文件。
【C代码33行】
从内存地址0x0800 017c拷贝数据0x40021018到r3中,也就是
r3 = * 0x0800 017c
也就是将pReg指针保存到r3中。
【C代码34行】
这里对应3条指令
首先将r3拷贝到r0中,然后将r0或上1左移3位,也就是
ORR r0,r0,#8
最后将r0的值写入r3所指地址中。
【C代码37行】
同33行,从内存地址0x0800 0180拷贝数据40010c00到r3中
【C代码38行】
同34行,这里也对应3条指令:
【C代码40行】
和33行不同的是,这里分了两条指令:
笔者认为前面是编译器优化了。根据ARM指令采用流水线机制,当前执行地址A的指令,同时已经在对下一条指令进行译码同时已经在读取下下一条指令:PC = A +4 (Thumb/Thumb2指令集)。因此前面类似的代码被优化了。
接下来就进入循环中。
后面就移植在死循环中,不断操作GPIO的亮灭。
【C代码45行】
这里是将B0设置为1,和34行类似。
【C代码47行】
这里将进入延时函数。
进入延时函数:
NOP是字节对齐,减少指令的内存访问次数。首先将变量d保存到r0,然后将r0赋给r1,接着是r0自减1,紧接着是r1与0比较,如果r1等于0,则会返回,否则,又从头开始,值得注意的是,这里先比较,然后r0才自减的。
为了进一步说明,可以看看–d的汇编代码。
这里就是相当于r1先减1,然后再比较的。
【C代码50行】
这行代码对应一下指令,很简单。
5 总结
在前面使用Keil进行了反汇编,也对相应的C代码进行了分析。我们看到的反汇编代码如下:
根据反汇编的代码,可将其对应到Flash,在Flash上的内容如下表所示:
地址 | Flash内容 |
---|---|
0x08000000 | 00000000 |
0x08000004 | 08000009 |
0x08000008 | f8dfd004 |
0x0800000c | f000f80c |
… | … |
最后总结下点灯的流程:
第一步:设置栈:CPU会从0x08000000读取值,用来设置SP。
第二步:跳转:CPU从0x08000004得到地址值,根据它的BIT0切换为ARM状态或Thumb状态,然后跳转。
第三步:对于cortex M3/M4,它只支持Thumb状态,所以0x08000004上的值bit0必定是1,0x08000004上的值 = Reset_Handler + 1。从Reset_Handler继续执行。
第四步:然后进入到主函数中执行相应C代码。
欢迎访问我的网站
BruceOu的哔哩哔哩
BruceOu的主页
BruceOu的博客
BruceOu的CSDN博客
BruceOu的简书
欢迎订阅我的微信公众号
以上是关于《嵌入式 - 嵌入式大杂烩》Keil反编译入门的主要内容,如果未能解决你的问题,请参考以下文章