我正在学习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?为什么我们在上面的例子中想要它?有人能给我一个我们真正需要它的例子吗?
谢谢!
答案 0 :(得分:8)
似乎有点混乱。这是一个解释:
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的值,但在程序计数器中,有效地返回该函数。