Chinaunix首页 | 论坛 | 博客
  • 博客访问: 278622
  • 博文数量: 58
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 600
  • 用 户 组: 普通用户
  • 注册时间: 2015-11-27 08:37
个人简介

从linux了解世界

文章分类
文章存档

2017年(5)

2016年(51)

2015年(2)

我的朋友

分类: 嵌入式

2016-01-02 17:26:58

函数跳转的两种方法:
1、bl    func
2、ldr   lr    返回地址
     ldr   pc   跳转地址
第一种方法,执行bl指令的时候会自动把返回地址写入lr(相对地址)。第二种方法,人为地把返回地址写入lr,再把跳转地址写入pc(绝对地址)。关于相对地址、绝对地址、链接地址、加载地址、地址有无关码的关系和概念可以看第一篇博客。
对于普通函数,通过试验查看c函数的反汇编代码,综合对比的结论如下:
1、当c函数简单、内部参数和变量较少时,从反汇编函数看也就是只用到R0-R3,R12寄存器的情况下:编译器只会在c函数的最后加一条BX    LR。为什么不需要保存这几个寄存器的原因是根据atpcs规则,这5个寄存器专门用来参数传递。
2、当c函数复杂,从反汇编函数看也就是R0-R3,R12这五个寄存器不够使用的情况下:编译器会在c函数的开始加上stmdb    sp!,{r4-r11,lr}c函数中用到哪个保存哪个,最多实际保存这9个,有时也会保存r4之前的寄存器到栈,但是这部分栈的内容是会被修改的),如果再加上这9个寄存器还不够用的话还会再加上一句sub    sp,sp,#立即数,然后就可以使用栈来传递参数和变量了。在c函数的最后相应的会有add    sp,sp,#立即数(如果之前有sub    sp,sp,#立即数)和ldria    sp!,{r4-r11,pc}
只要在使用c语言之前先设置好sp就可以了,不用自己在跳转c函数的前后编写现场保护和返回的代码。但是栈中的数据并不会清零只会把sp也就是栈顶的值复位(也就是跳转前后栈顶的指向不变)。还有就是汇编在跳转c函数前一定要先设置好lr的内容。

对于中断函数的编写在有两种方法:
1、把中断函数当做普通函数编写,这样的话在跳转该函数前要人为编写保存和恢复现场的汇编代码,例如:
                SUB     LR, LR, #4
                STMDB    SP!,{R0-R12,LR}
                LDR     LR, =INI_RETURN
                LDR     PC, =int_handle;int_handle为c函数
INI_RETURN
                ;BL         int_handle
                LDMIA    SP!,{R0-R12,PC}^
2、把c函数用__irq关键字修饰,声明为中断函数(gcc不支持__irq,mdk默认使用的armcc支持),中断函数反汇编之后和普通函数反汇编之后有区别。在中断函数前加入stmdb    sp!,{r0-r12,lr}(中断函数中用到哪个保存哪个,最多全部保存),如果寄存器不够用则sub    sp,sp,#立即数。在中断函数的最后相应的会有add    sp,sp,#立即数ldmia    sp!,{r0-r12,lr},最后通过subs    pc,lr,#4从中断返回。
    非常重要:发生中断时,lr会被硬件自动写入被中断的执行指令之后的第二条指令地址,原因是:硬件写lr寄存器时写入的是正在执行指令时的pc(pc是正在取址的指令地址,根据流水线结构为当前执行指令的地址+8,也就是被执行指令之后的第二条指令地址)-4也就是正在执行指令的下一个指令地址。但是中断的流程是,发生中断时把正在执行的一条指令执行完再处理中断,所以当前指令执行完pc已经更新也就是pc+4,这时处理中断,硬件写lr寄存器写入的是pc+4-4,就是pc(这里说的pc都是指,正在执行被中断指令时的pc值,就是被中断指令之后的第二条指令地址),所以实际上中断的返回地址应该为lr-4
    LDMIA    SP!,{R0-R12,PC}^可以参考下面附件的arm指令集pdf,大致的意思就是在中断模式下^表示把spsr付给cpsr,返回之前的工作状态跳出中断状态。subs赋值pc寄存器时,s表示更新cpsr,也就是把spsr给cpsr。
    在arm进行多寄存器操作时,最常用来保存恢复数据的指令为stmdb和ldria,这一对指令为普通寻址方式。也可以用stmfd和ldrfd代替,这一对指令为数据栈寻址方式。stmdb/ldria和stmfd/ldrfd是完全一样的。关于ldm/stm操作,地址和寄存器的对应关系可以看:

arm中断的处理过程可以看:
http://blog.chinaunix.net/uid-28458801-id-3780127.html
ARM指令集及汇编.pdf


阅读(3197) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~