好的,我想我明白你的问题了。
所以你有一些代码在一个函数调用一个函数
main ()
{
int a,b;
a = myfun0();
b=a+7;
...
所以当我们调用 myfun0() 时,链接寄存器基本上可以让我们返回,所以我们可以执行 b = a+7;理解当然所有这些都被编译为汇编和优化等等,但这足以理解链接寄存器用于在调用之后返回。
如果
myfun0 ()
{
return(myfun1()+3);
}
当 main 调用 myfun0() 时,链接寄存器指向 main() 函数中它需要返回的某些代码。然后 myfun0() 调用 myfun1() 它需要在返回 main() 之前返回 myfun0() 进行更多数学运算,因此当它调用 myfun1() 时,链接寄存器设置为返回并添加 3. 问题当我们将链接寄存器设置为返回到 myfun0() 时,我们会丢弃 main() 中需要返回的地址。因此,为了防止 IF 函数将调用另一个函数以及不能全部存在于一次性寄存器中的局部变量,必须将链接寄存器放入堆栈中。所以现在 main 调用 myfun0(),myfun0() 将调用一个函数 (myfun1()),因此链接寄存器的副本(将地址返回到 main())保存在堆栈中。 myfun0 调用 myfun1() myfun1() 遵循相同的规则,如果调用其他东西,则将 lr 放入堆栈,否则你不必这样做,myfun1() 使用 lr 返回到 myfun0(),myfun0() 从堆栈中恢复 lr 以便它可以返回主。遵循每个函数的简单规则,你不会出错。
现在中断不确定是否相关,或者我可能误解了您的问题。所以 arm 至少为非 cortex-m 内核存储了寄存器。但一般来说,当发生中断/异常时,如果异常处理程序需要使用前台任务正在使用的任何资源/寄存器,那么该处理程序需要将这些资源/寄存器保存在堆栈上,以便被中断的前台任务有不知道会发生这种情况,因为通常中断通常会发生在任意两条指令之间,因此您甚至需要保留在您中断之前由指令设置的标志。
因此,将其应用于 arm,您必须查看正在使用的架构,并查看它在哪里描述了中断过程,您必须保留哪些寄存器,哪些不需要,使用哪个堆栈指针等(您有如果您使用的是具有单独中断堆栈和前台堆栈的手臂,则在您的第一个异常之前进行设置)。
cortex-m 旨在为您完成部分/全部工作,它基本上只有一个堆栈,并且在中断时它会为您推送堆栈上的所有寄存器,因此您可以简单地让一个 C 编译函数作为处理程序和硬件在您之后清理(从保留的寄存器的角度来看)。其他一些处理器系列会为您执行类似的操作,它们可能会从中断指令中返回与返回指令分开,其中一个是因为在中断时硬件会保存标志和返回地址,但是对于简单的调用,您不需要保留标志.
arm 比其他一些指令集灵活得多,其他一些指令集可能没有任何指令允许您跳转到任何您想要的寄存器中的地址,您可能有限制。您可能受限于用作堆栈指针的寄存器,或者堆栈指针本身不能作为通用寄存器访问。按照惯例 sp 在 arm 中是 13,它们允许 push 和 pop 的伪指令转换为正确的 ldmia r13!{blah} 和 stmdb r13!,{blah} 但你可以选择你自己的(如果不使用编译器遵循约定或可以更改开源编译器以使用不同的堆栈指针寄存器)。手臂并不能阻止这一点。链接寄存器 r14 的神奇之处无非是分支链接或分支链接交换会自动修改 r14,但指令集允许您基本上使用任何寄存器来分支/返回以进行正常的函数调用。 arm 有足够的通用寄存器来鼓励编译器只做基于寄存器的参数传递而不是堆栈。一些处理器倾向于仅通过堆栈进行参数传递,并将其返回地址指令设计为严格基于堆栈,从而避免一起使用返回寄存器,并且在嵌套函数时必须保存该规则。
所有这些方法都有利有弊,如果希望传递 arm 寄存器并且基于寄存器的返回地址也是如此,但是对于嵌套函数,您必须在每个嵌套级别保留返回地址以免丢失。同样,对于打断,您必须按照您找到它们的方式放回原处,并且能够回到您打断前台的位置。