Chinaunix首页 | 论坛 | 博客

fx

  • 博客访问: 1347005
  • 博文数量: 115
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 3964
  • 用 户 组: 普通用户
  • 注册时间: 2013-05-02 14:36
文章分类
文章存档

2022年(2)

2019年(2)

2018年(10)

2017年(1)

2016年(50)

2015年(12)

2014年(9)

2013年(29)

分类: 嵌入式

2016-08-31 21:17:44

环境: keil 5.14

MCU: 一款M0的处理器

 

主要是解决以下问题: 函数嵌套调用过程中LR的处理,以及中断发生时LR的处理。

 

 

测试代码如下

uint8_t add(uint8_t a, uint8_t b){

         uint8_t c;

         c = a+b;

         return c;

}

 

uint8_t test_fun(uint8_t a,uint8_t b, uint8_t c, uint8_t d,uint8_t e){

         uint8_t ret;    

         ret = add(a,b);        

         return ret;

}

int main(void){

         uint8_t i;

         uint8_t k;

        

         i = add(1,2);

         k = test_fun(2,3,4,5,6);

        

         while(1);        

         return 0;

}


Main函数汇编代码

main汇编代码来看,参数12放入r0r1中然后调用add函数,

BL指令在调用add函数时会同时将返回地址存入LR寄存器中


Add汇编代码如下:

计算了r0+r1的和 之后保存到r0,因为 bl调用add的时候就在lr中自动保存了返回地址,所以这里直接通过bx lr就可以让函数返回到main



之后main执行test_fun函数

main汇编中看到,参数 2 3 4 依次被保存到r0-r3中,参数6被保存到栈中,这也遵循ATPCS规定的函数传参规则




 

最后是test_fun的汇编代码,因为test_fun中用到了r4-r7所以 首先push保存了一下这几个寄存器的值,以方便后面恢复。 同时也将 LR的值压栈了。 前面add的汇编中我们看到是没有对LR压栈的,这里却有是因为test_fun里面还调用了add函数,通过BL函数调用时回改变LR的值,所以test_fun的第一句就 将这个LR保存了。

 

之后提取参数a e两个参数,然后调用add函数,最后通过pop来返回到man

 

对参数e的提取,因为 M0 栈向低地址增长,而函数入口将r4-r7,lr又入栈了,所以之前存的参数e,即数据6SP+4*5地址处



综上:

          对于LR的处理,主要是看 函数内部是否有其他函数的调用,如add函数,其内部并无其他函数调用,而 BL add时就已经将返回地址存入LR中了,所以整个过程中LR就没处理,最后函数返回直接 BX LR就可以了

         test_fun函数内部存在其他函数调用,既然存在其他函数调用就会破坏LR的值,所以函数第一句就先将 LR保存在栈中,而函数返回直接出栈将值放入PC中即可。

 

PS:对于中断,M0,M3等会自动将r0-r3 r12,LR, 返回地址PC,程序状态寄存器自动压栈。

即中断并不像普通的函数调用,中断的返回地址是在PC中并被入栈,那么LR保存的意义何在?

 

原因在于,M0M3等处理器的中断返回机制,在将上面所说的中断发生后 自动将一些寄存器值入栈后,LR的会被更新为异常返回特殊值(EXC_RETURN),作用是中断返回时,LR将这个值放入PC便可以触发返回机制。具体的查阅M0,M3相关手册

 

也就是发生中断后,LR的值会被修改。

 

那么如果中断是 在test_fun这种内部有其他函数调用的函数 执行时发生的,并且第一句PUSH已经执行了,那么因为LR中的返回地址其实已经被push到栈中了,这个时候中断发生了,保不保存并不影响,即使中断触发会导致LR的值被破坏,但是毕竟我们已经保存了。

 

但是如果中断发生在add这类函数内部没有其他函数调用的 函数中时,因为add函数中并未自己在函数一开始就保存好自己的返回值,这个时候中断发生如果不保存LR的值,LR的值随后又会被修改,那么就会导致出错了。

 

综上,对于中断触发时保存LR的 目的在于  LR虽然不是中断自己的返回值,但是之前一个状态的返回值。




阅读(2582) | 评论(0) | 转发(0) |
0

上一篇:插入排序和希尔排序

下一篇:堆排序

给主人留下些什么吧!~~