简单的例程,几个函数调用,来查看寄存器状态,主要是学习一下cortem-M核中LR寄存器的理解:
例程源码:
static uint32_t count_test = 0;
static void fun3()
{
count_test++;
}
static void fun2()
{
count_test++;
fun3();
count_test++;
}
static void fun1()
{
count_test++;
fun2();
count_test++;
}
int main(void)
{
fun1();
return 0;
}
通过单步调试来查看各个寄存器状态:
step1
进入调试界面
- c源代码
- 对应的汇编代码
- 对应的当前寄存器
step2
记录当前进入main函数所要做的动作和记录的状态
1、因main()函数中还有子函数,所以需将r4,lr寄存器压入栈中,对应的汇编:
0x0800017A B510 PUSH {r4,lr}
2、记住当前main函数中return 0处的代码地址:0x08000180
在进入fun1()函数后,会将返回地址的指针加1保存到LR寄存器中,即0x08000181,请记住这个值。
step3
进入fun1()
1、查看当前LR寄存器为0x08000181,与上述分析一致;
2、进入当前fun1()函数中后,因为有子函数要执行,所以依然将r4,lr寄存器压入栈中
3、记录代码中counnt_test++代码对应的地址:0x0800172,那么进入到fun2()函数之后的LR值应为:0x0800173
step4
进入fun2()
分析同上,
step5
进入与退出fun3()
1、因fun3()函数中,没有子函数,r4,lr寄存器没有再进行入栈操作,执行结束之后直接返回,根据LR寄存器保存的返回地址:
step6
退出到fun2()并准备进入fun3()
1、退出到fun2()时,因当前LR寄存器保存的还是进入fun3()时的值,现在要从退出到fun2()到退出到fun1(),那么对应的LR肯定就不对了,需进行出栈操作,如上图的汇编,将r4,pc出栈操作(pc就是lr,直接将lr的值赋给pc并执行),栈中存放的就是退出到fun1()地址处的值:
0x08000162 BD10 POP {r4,pc}
step7
退出到fun1()并准备进入main()
道理同上。
step8
最终进入main()函数。
所以要记住的是:
1、每次调用子函数,都会将返回的地址加1保存到LR寄存器中;
2、如当前函数中还有子函数,则在进入子函数前需先压栈r4,lr,进行保护现场操作;
3、而从函数中退出时,如果当前函数中有子函数,有过入栈操作,则在退出此函数时需进行出栈操作,根据出栈中保存的lr寄存器来返回需要退出的函数位置处。
本文只是做了简单的记录,方便日后查看,后续再学习一下cortex-M核的几种工作模式及权限。