我正在学习 ARM 汇编,现在我遇到了一些问题。
我知道链接寄存器,如果我没记错的话,它保存着函数调用完成时要返回的地址。
因此,如果我们有类似的东西(取自 ARM 文档):
0 | here
1 | B there
2 |
3 | CMP R1, #0
4 | BEQ anotherfunc
5 |
6 | BL sub+rom ; Call subroutine at computed address.
那么,如果我们将左侧的列视为每条指令的地址,那么在地址 1 处的 B 之后,链接寄存器的值就是 1,对吧?
然后程序转到那里的方法,然后它使用链接寄存器的值来知道返回到哪里。
如果我们现在跳到地址6,我被困住了,我们知道BL将下一条指令的地址复制到lr(r14,链接寄存器)中。
所以现在它会复制 sub 的地址,它是一个子程序(什么是子程序??)+ rom (这是一个数字?)或 sub+rom 的地址(我不知道这可能是什么)。
但一般来说,我们什么时候需要BL?为什么我们在上面的例子中需要它?有人可以给我一个我们真正需要它的例子吗?
谢谢!
好像有点混乱。这是一个解释:
B
指令将分支。它跳转到另一条指令,并且没有预期的返回。链接寄存器 (LR) 未被触及。
BL
指令会分支,但也会链接。 LR会加载内存中BL
之后指令的地址,而不是BL
之后执行的指令。然后就可以使用 LR 从分支返回。
示例:
start:
01: MOV r0, r2 ; some instruction
02: B there ; go there and never return !
there:
11: MOV r1, r0 ; some instruction
12: BL some_function ; go to some_function, but hope to return !
; this BL will load 13 into LR
13: MOV r5, r0
14: BL some_function ; this BL will load 15 into LR
15: MOV r6, r0
some_function:
MOV r0, #3
B LR ; here, we go back to where we were before
如果你想在函数内调用另一个函数,LR会被覆盖,所以你将无法返回。常见的解决方案是使用
PUSH {LR}
将 LR 保存在堆栈上,并在返回之前使用 POP {LR}
恢复它。您甚至可以在单个 POP {PC}
中恢复和返回:这将恢复 LR 的值,但在程序计数器中,有效地返回函数。