由于论坛有字数限制,接上一篇“教你如何找到导致程序跑飞的指令(一)”,或者下载附件查看全文,或者登录我博客查看全文。
好了,ARM7内核的介绍到此结束,下面介绍cortex内核的,使用ST的STM32、TI的LM3S系列的同学们注意了,它们都是cortex内核的,下面的介绍你也许用得上。
Cortex内核与ARM7内核定位此种问题的思路完全是一样的,cortex内核的详细介绍请参考“底层工作者手册之嵌入式操作系统内核”中的5.1节。cortex内核有一些特殊,它在产生中断时会先将R0~R3、R12、LR、PC以及XPSR这8个寄存器压入当前的堆栈,然后才跳转到中断向量表执行中断服务程序,此时LR中保存的不是返回地址,而是返回时所使用的芯片模式和堆栈寄存器的标示,只能是0xFFFFFFF1、0xFFFFFFF9或者是0xFFFFFFFD这3个值中的一个,如果你还认为LR中保存的是返回地址,并且是这么奇特的地址,估计你一定会晕了。
要找cortex内核芯片的返回地址就需要到栈中去找,前面不是说了么,进入中断前硬件会自动向当前栈压入8个寄存器,如下图所示:
图6
如果你看了2.3节和5.1节就应该知道cortex和ARM7内核都是一种递减满栈,意思是说压栈时栈指针向低地址移动,栈指针指向最后压入的数据。SP(R13)寄存器就是栈寄存器,它里面保存的就是当前的栈指针,因此当cortex内核发生中断时,我们就可以根据SP指针来找到压入上述8个寄存器的地址,然后找到LR的位置,再从LR中找到返回地址,下面的这个例子是“底层工作者手册之嵌入式操作系统内核”中的6.1节的一个例子,
void TEST_TestTask1(void)
{
while(1)
{
DEV_PutStrToMem((U8*)"\r\nTask1 is running! Tick is: %d",
MDS_SystemTickGet());
DEV_DelayMs(1000);
MDS_TaskDelay(250);
if(MDS_SystemTickGet() >= 2000)
{
ADDRVAL(0xFFFFFFFF) = 0;
}
}
}
红色字体部分会触发一个异常,它会向0xFFFFFFFF这个地址写入0,也会触发一个异常中断,触发的异常会进入MDS_FaultIsrContext异常中断服务函数,在MDS_FaultIsrContext函数的入口地址打上断点,运行此程序,触发异常后如下图 :
图7
从图7左上侧窗口可以看到SP的值为0x20001258,那么我们在右下角的窗口找到0x20001258这块内存的地址,从0x20001258开始,每4个字节对应一个寄存器,依次为R0、R1、R2、R3、R12、LR、PC、XPSR,其中红框的位置就对应着LR,从图中可以看到LR的值为0x1669,我们找到这个版本编译后的目标文件,使用objdump软件反汇编,如下图所 示:
图8
可以看到0x1669这个地址位于TEST_TestTask1函数里,与我们设计的一致。
这段代码是经过O2优化的,汇编指令对照到C指令上会有些费事,这里就不再讲解了,知道方法就好,剩下的自己研究。
这里面有2点说明一下,一是cortex内核支持双堆栈,如果使用双堆栈的话会复杂一点,这里为了简单的说明问题,我们只使用了其中的一个MSP,另外一个PSP没有使用,在这个例子里你只需要认为只有一个SP就可以了。另外一点是0x1669这个地址其实就是0x1668,因为cortex内核采用的是Thumb2指令集,该指令集要求指令的最后一个bit为1,因此0x1668就变成了0x1669。
上面介绍ARM7内核的时候我不是说过如果在FaultIsr函数里做一个打印功能就可以通过打印信息来定位这种问题么,其实在介绍cortex内核的这个例子中我就做了这个功能,具体的实现就先不介绍了,有兴趣的同学可以看我6.1节的介绍(2012.02.28,目前book还没写到6.1节),下面是出现异常时打印的一小段信息,从这段信息里我们可以看到SP(R13)的数值为0x20001258,与图7的情况一样,那么在栈中从0x20001258这个地址向上找,找到栈中保存LR的位置,它的数值就是0x1669,与图7中的分析是一致的。
注意一点蓝色字体的R14是我这段打印程序还原过的,因此它与内存中的数值是一样的。
R15 = 0x00000536 R14 = 0x00001669
R13 = 0x20001258 R12 = 0x00000000
R11 = 0x00000000 R10 = 0x00000000 R9 = 0x00000000 R8 = 0x00000000
R7 = 0x00000000 R6 = 0x000003E8 R5 = 0x000007D0 R4 = 0x00000000
R3 = 0x0000008C R2 = 0x00000000 R1 = 0xE000ED04 R0 = 0x00000834
XPSR= 0x21000000
0x20001274: 0x21000000
0x20001270: 0x00000536
0x2000126C: 0x00001669
0x20001268: 0x00000000
0x20001264: 0x0000008C
0x20001260: 0x00000000
0x2000125C: 0xE000ED04
0x20001258: 0x00000834
更多信息,欢迎访问我的博客blog.sina.com.cn/ifreecoding
|