Phi*_*wak 2 assembly stack branch arm
我试图LR在调用BL指令之前更好地理解你为什么要推动。我知道该BL指令会在将 PC 恢复到 BL 调用之后的指令地址之前分支到另一个子例程,但为什么在调用LR之前会推送?BL我已经编写了下面用于阶乘计算的完整递归代码以提供上下文。a 和 b 都是用伪代码编写的变量。
LDR RO, a
PUSH (LR)
BL factorial
STR R0, b
POP (LR)
factorial:
CMP RO, #0
MOVEQ R0, #1
MOVEQ PC, LR
MOV R3, R0
SUB R0, R0, #1
PUSH (R3, LR)
BL factorial
MUL R0, R3, R0
POP (R3, LR)
MOV PC, LR
Run Code Online (Sandbox Code Playgroud)
我理解这个程序应该如何流动,但我对堆栈中存储的地址感到困惑。显然,您希望在第一次分支调用后将“”指令的地址STR R0, b放入堆栈中,但是如果在LR调用之前将其压入堆栈,则如何将其保留在堆栈上BL?
但是为什么在调用BL之前先推送LR呢?
在这里您可以看到递归的成本。从更高级别的编码角度来看,递归看起来很简单。状态由编译器存储在堆栈帧中。只有一个LR寄存器适合叶函数。然而,如果你有一个扩展的调用链,“A调用B调用C调用D”,那么当在“D”中执行并返回LR到“C”时,必须存储“A,B和C”的返回地址。对于递归来说,“A、B、C、D”都是相同的。
有关详细信息,请参阅:ARM 链接寄存器和帧指针。
我相信看到这些额外的说明是有启发性的。通常可以形成循环而不是递归,并且线性流程将执行得更快,并且使用相同数量的变量和更少的代码。堆栈帧和操作对于使用高级语言的程序员来说是隐藏的。
由于“尾递归”,不需要框架也是很常见的。实际上,只有第一次调用阶乘需要保存返回地址,而不是bl简单的b即可。