分类: LINUX
2011-08-10 22:10:50
pc寄存器保存的总是当前正在取指的指令的地址。
如果有如下指令序列S1,S2,S3,S4,S5这五条指令在内存中分布为:
PC寄存器保存的总是当前正在取址的指令的地址,arm态下指令长度为4个字节,如图所示当前正在执行的指令为pc-8即pc的值为当前正在执行的指令加8同理在arm9五级流水的情况下:
了解一下pc与arm处理指令的过程有利于我们理解异常处理进入时lr保存的pc值 与函数返回时所要执行的指令之间的关系。
在异常发生时常常要保存当前指令地址,即pc保存到lr中。以用来异常处理完毕的返回。
要清楚返回地址,我们必须弄清楚三点:
1.该种异常或者程序跳转发生在什么时候?
2.异常发生时pc的值是否更新
3.异常返回时要接着执行的指令是哪一条?
接着我们来看看各种异常发生后 进入处理函数 处理完毕如何返回 返回包含如下两个操作:在谈异常返回pc的值与lr_mode之间的换算关系前 先看看两个跳转指令B 和 BL
还有一点我们要清楚的是PC总是指向当前正在执行的指令的下两条指令 即pc指向的是当前正在取址的指令
对比一下两个代码:
这两段代码的执行效果是一样的 只是第一段代码采用B指令跳转的 我们要清楚当前执行的指令为mov lr,pc 而当前取指的指令为add r0,r0,r1 所以pc保存的是add r0,r0,r1的地址 所以执行完mov lr,pc后 lr保存的也是add r0,r0,r1的地址
而第二段指令采用BL跳转 lr的值由arm计算得到 其实当执行bl main的时候 pc指向的是sub r0,r3,r2 但是arm核自动保存pc-4到LR中(arm态) thumb态下为PC-2
所以跳转的返回只需要mov pc,lr 上面两个跳转就能正常的返回了。
之所以对比这两个 我想弄清楚的是 当arm核自动保存返回地址到lr中的情况下 arm状态总是保存pc-4 thumb状态保存pc-2 也就是说自动保存的lr总是指向当前执行指令的下一条指令现在可以来分析一下各种异常处理返回时如何手动编码了 (*^__^*) 嘻嘻…… 当然这个不可能自动编码 自动编码的是进入异常 (*^__^*) 嘻嘻……
1.SWI和未定义指令异常中断处理程序的返回我们还是以S1,S2,S3,S4,S5的指令序列为例:
SWI和未定义指令异常是执行的指令触发的,如果当前执行的指令为S1,即触发SWI和未定义指令异常的指令是S1,此时PC指向的是S3(S3此时取指),异常发生时arm核自动将PC-4(arm态)或者PC-2(thumb态)存入LR_mode,级LR_mode保存的是S2的地址。而SWI和未定义指令异常返回时应该进行取指操作的指令为触发异常的指令的下一条指令即S2所以返回时应有的PC值和LR相等。
所以在不使用堆栈数据的时候,可以用如下指令返回
这里MOVS区别于mov的是:movs在将LR赋给PC的同时,将SPSR_mode赋给CPSR
而在使用堆栈的情况下就应该用以下指令处理了
注意这里^表示在指令执行的同时将SPSR_mode赋给CPSR
2.IRQ和FIQ异常中断处理程序的返回
这两类中断发生在当前指令执行完毕之后,arm核查询发现有中断发生才触发的异常,此时PC已经更新。如果当前刚执行完毕S1指令,PC更新指向了S4指令,此时触发了IRQ或者FIQ异常,则LR自动保存的值为PC-4(arm态)或者PC-2(thumb态)此时LR_mode保存的是S3的地址。而异常返回时应该执行的指令为S2,所以我们返回时可以采用如下指令返回:不使用堆栈的情况下:
使用堆栈的情况下:
3.指令预取终止异常中断处理程序的返回
指令预取终止异常发生在指令执行期,其实在指令取指的时候已经被标识为有问题的指令,只是在执行时才触发异常,而指令预取终止异常返回时仍需对这条指令重新取指。比如S1执行时触发了指令预取终止异常,则LR_mode保存的是S2的地址,而返回时需要重新取指。所以,返回取址的指令为S1,即PC-4(arm态)或者PC-2(thumb态)
所以返回时可以用如下方式:
不使用堆栈的情况下:
使用堆栈的情况下:
4.数据访问终止异常中断处理程序的返回
数据访问终止异常是指令在访存期触发的,比如触发该异常的为S1,则当前执行的指令为S2,PC执行的指令为S4,当异常发生时LR_mode保存的是S3的地址,而数据访问终止异常返回时要求重新取指该异常指令。所以,返回取址的指令为S1,即PC-8(arm态)或者PC-4(thumb态)
所以返回时可以用如下方式:
不使用堆栈的情况下:
使用堆栈的情况下:
====