kei反汇编分析

只分析   《点亮LED灯》中的一段

1.C语言代码

GPIOB->BRR = GPIO_Pin_11;//PB11输出低电平

等价于

 *(int*)(0x40010c14)= 0x0800;  //向地址0x40010c14上写0x0800

2.汇编代码

0x080001D6 F44F6000  MOV      r0,#0x800
0x080001DA 4908      LDR      r1,[pc,#32]  ; @0x080001FC
0x080001DC 6008      STR      r0,[r1,#0x00]

。。。。

0x080001FC 0C14      DCW      0x0C14
0x080001FE 4001      DCW      0x4001

3.代码分析

1)mov指令      

MOV{条件}{S}  目的寄存器,源操作数

MOV指令可完成从另一个寄存器、被移位的寄存器或立即数赋值到目的寄存器。其中S选项为指令的操作结果是否操作CPSR中的条件标志位,当没有S选项时指令不更新CPSR中的条件标志位结果。

MOV   R0,R1 ; R0 = R1;

MOV  PC,R14 ;PC = R14;

MOV   R0,R1,LSL#3 ;R0=R1<<3;

0x080001D6 F44F6000  MOV      r0,#0x800     即:将0x800放在r0寄存器中

2)LDR指令

LDR指令的格式: 

LDR{条件}   目的寄存器     <存储器地址>

作用:将 存储器地址 所指地址处连续的4个字节(1个字)的数据传送到目的寄存器中。

LDR指令的寻址方式比较灵活,实例如下:

LDR R0,[R1]                                                      ;将存储器地址为R1的字数据读入寄存器R0。

LDR R0,[R1,R2]                                             ;将存储器地址为R1+R2的字数据读入寄存器R0。

LDR R0,[R1,#8]                                             ;将存储器地址为R1+8的字数据读入寄存器R0。

LDR R0,[R1],R2                                               ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2的值存入R1。

LDR R0,[R1],#8                                               ;将存储器地址为R1的字数据读入寄存器R0,并将R1+8的值存入R1。

LDR R0,[R1,R2]!                                          ;将存储器地址为R1+R2的字数据读入寄存器R0,并将R1+R2的值存入R1。

LDR R0,[R1,LSL #3]                                   ;将存储器地址为R1*8的字数据读入寄存器R0。

LDR R0,[R1,R2,LSL #2]                         ;将存储器地址为R1+R2*4的字数据读入寄存器R0。

LDR R0,[R1,,R2,LSL #2]!                       ;将存储器地址为R1+R2*4的字数据读入寄存器R0,并将R1+R2*4的值存入R1。

LDR R0,[R1],R2,LSL #2                            ;将存储器地址为R1的字数据读入寄存器R0,并将R1+R2*4的值存入R1。

LDR R0,Label                                                ;Label为程序标号,Label必须是当前指令的-4~4KB范围内。

要注意的是

LDR Rd,[Rn],#0x04                                                              ;这里Rd不允许是R15。

另外LDRB 的指令格式与LDR相似,只不过它是将存储器地址中的8位(1个字节)读到目的寄存器中。

LDRH的指令格式也与LDR相似,它是将内存中的16位(半字)读到目的寄存器中。

LDR R0,=0xff

这里的LDR不是arm指令,而是伪指令。这个时候与MOVE很相似,只不过MOV指令后的立即数是有限制的。这个立即数必须是0X00-OXFF范围内的数经过偶数次右移得到的数,所以MOV用起来比较麻烦,因为有些数不那么容易看出来是否合法。

0x080001DA 4908      LDR      r1,[pc,#32]  ; @0x080001FC     即:将存储器地址为(当前存储器地址+32)的字数据读入寄存器R1。在cortex-m3权威指南的第六章中有一句话,“由于流水线的存在,以及处于对Thumb代码兼容的考虑,读取PC会返回当前指令地址+4。这个偏移量总是4,不管是执行16位指令还是32位指令,这样就保证了在thumb和thumb2之间的一致性”。也就是说,CM3要么每次读取两条16位的指令,要么每次读取一条32位的指令。 

这里出现了一个让人疑惑的事情,就是按照上面所述进行计算的话.pc=0x080001DA +4=0x080001DE,然后执行LDR      r1,[pc,#32]  ;得到的地址是0x080001FE。这与反编译得到的结果不一样,然后我纠结了一天。

查看《深入理解计算机系统》,在里面找到一张图,也不知道自己理解的对不对,拿出来与大家分享自己的想法。

假设A阶段取指,B阶段译码,C阶段执行。

第一条指令进入C阶的时候,也就是第三个时间点(time=300)时,这个时候C开始执行,有可能已经开始取PC值。但此时第三条指令刚刚开始进入A阶段(取指),B阶段(开始译码)。A寄存器(PC寄存器)的值还没有更改,也就是说还是第二指令的地址,即PC=当前指令地址+2。得到PC值为0x080001DC。

然后进行下一步,第一条指令的C阶段接着执行,A、B阶段跟进,到最后time=359的时候,也就是第4阶段,A取指结束,B译码结束,C执行结束,等多了359这个时间点,刷新寄存器。PC=当前指令地址+4。

如果是这么思考的话,就能和指令手册上面所述内容对应上了。 得到地址0x080001FC。将这个地址的字数据放入R1寄存器中

找到0x080001FC。这个地址的内容是:

0x080001FC 0C14      DCW      0x0C14

0x080001FE 4001      DCW      0x4001

这里有个注意的点是:大小端问题。

[注意]:STM32是小端模式,意思是他把低字节数据保存在低地址,高字节数据保存在高地址。大端模式在保存的时候,他把低字节数据保存在高地址,高字节数据保存在低地址。(按照我们的书写习惯,我觉得大端模式,我们看着舒服。)

那么其实这里的数据就是0x40010C14,这个数据其实就是BRR寄存器的地址。

3)STR指令

STR指令的格式为:

STR{条件} 源寄存器,<存储器地址>

STR指令用于从源寄存器中将一个32位的字数据传送到存储器中。该指令在程序设计中比较常用,且寻址方式灵活多样,使用方式可参考指令LDR

指令示例:

STR   R0,[R1],#8    ;将R0中的字数据写入以R1为地址的存储器中,并将新地址R1+8写入R1。

STR   R0,[R1,#8]    ;将R0中的字数据写入以R1+8为地址的存储器中。

0x080001DC 6008      STR      r0,[r1,#0x00]

它将0x800送入地址为0x40010C14的存储器中,起到了设置寄存器的目的。

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

孙八瓶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值