首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

入门ARM实例 test4

入门ARM实例 test4

  • #include <stdio.h>
  • void f1()  
  • {  
  • }  
  • void main()  
  • {  
  •   int d = 4;  
  •   f1();  
  • }  
      然后编译:arm-linux-gnueabihf-gcc test.c -o test4
      然后看看汇编代码:
0000835c <f1>:
1    835c:       b480            push    {r7}
2    835e:       af00            add     r7, sp, #0
3    8360:       46bd            mov     sp, r7
4    8362:       bc80            pop     {r7}
直接跳到main函数里调用此函数时保存的LR值:
5    8364:       4770            bx      lr
6    8366:       bf00            nop

00008368 <main>:
程序用到了r7寄存器,所以需要保护以免破坏之前的数据,同时因为本函数调用子函数f1,需要用到lr寄存器保存返回值,故需要保存LR到栈里:

7    8368:       b580            push    {r7, lr}
8    836a:       b082            sub     sp, #8
9    836c:       af00            add     r7, sp, #0
10    836e:       f04f 0304       mov.w   r3, #4
11    8372:       607b            str     r3, [r7, #4]
跳转到函数f1的地址,同时把返回地址保存到LR寄存器:
12    8374:       f7ff fff2       bl      835c <f1>
13    8378:       f107 0708       add.w   r7, r7, #8
14    837c:       46bd            mov     sp, r7
注意:此时不再使用bx lr返回了!
而是直接把第7行保存的LR值弹到PC寄存器上,下一条取地址指令就是取main函数的下一个地址。
其实,采用原来的方式:pop {r7, lr} 以及 bx lr 返回也是可以的,只不过会多使用一条指令:
15   837e:       bd80            pop     {r7, pc}
        细心的人会发现,汇编代码8-11行与
《从最简单的实例学习ARM 指令集(一)》中的范例test1.c一模一样,f1函数的机器指令十分简单,就是r7寄存器的压栈与出栈,相信大家都能看懂。不知道大家有没有注意到,从main函数跳转到f1用的是bl指令,而从f1返回调用的是bx指令?
        其实这是因为涉及到arm处理器的两种工作状态:arm和thumb,子函数返回需要判断lr寄存器的[0]位来决定arm工作在那种状态,对子函数来说,偷懒的做法就是:不管主函数是什么,返回是尽管使用bx,让arm自己判断。而对main函数这样调用者来说,是知道当前处理器工作在thumb还是arm状态的,所以只需要使用bl就可以了。
       总结一下子函数的调用规则就是:bl用在函数内,bx用在返回。
返回列表