微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > ARM汇编 MOV PC,LR

ARM汇编 MOV PC,LR

时间:11-09 来源:互联网 点击:

终于明白这个LR寄存器了

看下面这个ARM汇编

BL NEXT ;跳转到子程序

......... ;NEXT处执行

NEXT

..........

MOV PC,LR ;从子程序返回

这里的BL是跳转的意思,LR(R14)保存了返回地址

PC(R15)是当前地址,把LR给PC就是从子程序返回

这里有一下总结

首先

1.SP(R13) LR(R14)PC(R15)

2.lr(r14)的作用问题,这个lr一般来说有两个作用:
1》.当使用bl或者blx跳转到子过程的时候,r14保存了返回地址,可以在调用过程结尾恢复。
2》.异常中断发生时,这个异常模式特定的物理R14被设置成该异常模式将要返回的地址。

另外注意pc,在调试的时候显示的是当前指令地址,而用mov lr,pc的时候lr保存的是此指令向后数两条指令的地址,大家可以试一下用mov pc,pc,结果得到的是跳转两条指令,这个原因是由于arm的流水线造成的,预取两条指令的结果.

3.》我以前看书不懂的地方

子程序返回的三种方法

现在总结如下

1.MOV PC,LR

2.BL LR

3.在子程序入口处使用以下指令将R14存入堆栈

STMFD SP!,{,LR}

对应的,使用以下指令可以完成子程序的返回

LDMFD SP!, {,LR}

转载自:http://blog.csdn.net/xgx198831/article/details/8333446

汇编学习总结记录

1.1. 汇编学习总结记录
对于我们之前分析的start.S中,涉及到很多的汇编的语句,其中,可以看出,很多包含了很多种不同的语法,使用惯例等,下面,就对此进行一些总结,借 以实现一定的举一反三或者说触类旁通,这样,可以起到一定的借鉴功能,方便以后看其他类似汇编代码, 容易看懂汇编代码所要表达的含义。
1.1.1. 汇编中的标号=C中的标号
像前面汇编代码中,有很多的,以点开头,加上一个名字的形式的标号,比如:

  1. reset:
  2. /*
  3. * set the cpu to SVC32 mode
  4. */
  5. mrs r0,cpsr

中的reset,就是汇编中的标号,相对来说,比较容易理解,就相当于C语言的标号。
比如,C语言中定义一个标号ERR_NODEV:

  1. ERR_NODEV: /* no device error */
  2. ... /* c code here */

然后对应在别处,使用goto去跳转到这个标号ERR_NODEV:

  1. if (something)
  2. goto ERR_NODEV ;


汇编中的标号 = C语言中的标号Label
1.1.2. 汇编中的跳转指令=C中的goto
对应地,和上面的例子中的C语言中的编号和掉转到标号的goto类似,汇编中,对于定义了标号,那么也会有对应的指令,去跳转到对应的汇编中的标号。
这些跳转的指令,就是b指令,b是branch的缩写。
b指令的格式是:
b{cond} label
简单说就是跳转到label处。
用和上面的例子相关的代码来举例:

  1. .globl _start
  2. _start: b reset

就是用b指令跳转到上面那个reset的标号。

汇编中的b跳转指令 = C语言中的goto
1.1.3. 汇编中的.globl=C语言中的extern
对于上面例子中:

.globl _start
中的.global,就是声明_start为全局变量/标号,可以供其他源文件所访问。
即汇编器,在编译此汇编代码的时候,会将此变量记下来,知道其是个全局变量,遇到其他文件是用到此变量的的时候,知道是访问这个全局变量的。
因此,从功能上来说,就相当于C语言用extern去生命一个变量,以实现本文件外部访问此变量。

汇编中的.globl或.global = C语言中的extern
1.1.4. 汇编中用bl指令和mov pc,lr来实现子函数调用和返回
和b指令类似的,另外还有一个bl指令,语法是:
BL{cond} label
其作用是,除了b指令跳转到label之外,在跳转之前,先把下一条指令地址存到lr寄存器中,以方便跳转到那边执行完毕后,将lr再赋值给pc,以实现函数返回,继续执行下面的指令的效果。
用下面这个start.S中的例子来说明:

  1. bl cpu_init_crit
  2. 。。。
  3. cpu_init_crit:
  4. 。。。
  5. mov pc, lr

其中,就是先调用bl掉转到对应的标号cpu_init_crit,其实就是相当于一个函数了,
然后在cpu_init_crit部分,执行完毕后,最后调用 mov pc, lr,将lr中的值,赋给pc,即实现函数的返回原先 bl cpu_init_crit下面那条代码,继续执行函数。
上面的整个过程,用C语言表示的话,就相当于

  1. 。。。
  2. cpu_init_crit();
  3. 。。。
  4. void cpu_init_crit(void)
  5. {
  6. 。。。
  7. }


而关于C语言中,函数的跳转前后所要做的事情,都是C语言编译器帮我们实现好了,会将此C语言中的函数调用,转化为对应的汇编代码的。
其中,此处所说的,函数掉转前后所要做的事情,就是:
函数跳转前:要将当前指令的下一条指令的地址,保存到lr寄存器中。
函数调用完毕后:将之前保存的lr的值给pc,实现函数跳转回来。继续执行下一条指令。
而如果你本身自己写汇编语言的话,那么这些函数跳转前后要做的事情,都是你程序员自己要关心,要实现的事情。

汇编中bl + mov pc,lr = C语言中的子函数调用和返回
1.1.5. 汇编中的对应位置有存储值的标号 = C语言中的指针变量
像前文所解析的代码中类似于这样的:

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top