谁能向我解释为什么我们在这里测试链接寄存器的值?
将把的bl check_position
值PC+4
放在链接寄存器中,并将控制权转移给check_position
PC 相关人员。bl at ARM 到目前为止,一切都是PC
相对的。
从文字池中ldr r1,=check_position
获取一个值。Ref1 实际代码看起来像,
ldr r1,[pc, #offset]
...
offset:
.long check_position # absolute address from assemble/link.
因此R0
包含 PC 相对版本和R1
包含绝对组装版本。在这里,它们进行了比较。您还可以使用算术计算差异,然后如果非零则分支到它;或者可能将代码复制到它的绝对目的地。Ref2 如果代码在链接地址运行,则和是相同的。这是一些针对.R0
R1
pseudo code
bl
mov lr,pc ; pc is actually two instruction ahead.
add pc,pc,#branch_offset-8
关键是一切都BL
基于. 除了提前 8 个字节之外,我们可以使用,而不是使用这个技巧。另一种选择是使用,这将使汇编程序为我们完成所有地址数学运算。PC
lr
mov R0,PC
PC
adr R0,check_position
/* Test if we are running from an address, we are not linked at */
check_position:
adr r0, check_position
ldr r1, =check_position
cmp r0, r1 /* ; don't relocate during debug */
beq relocated_entry
ARMv6 版本可能如下所示,
/* Test if we are running from an address, we are not linked at */
check_position:
adr r0, check_position
movw r1, #:lower16:check_position
movt r1, #:upper16:check_position
cmp r0, r1 /* ; don't relocate during debug */
beq relocated_entry
在这两种情况下,代码都更直接,缩小了一个字并且不会覆盖lr
寄存器,因此它可以用于其他目的。
Ref1:参见gnu-assembler 手册中的Arm op-codes和.ltorg
Ref2:这正是 Linuxhead.S
为 ARM 所做的。
编辑:我检查了 ARM ARM 并且 PC 显然是当前指令+8
,这说明了为什么代码是这样的。我认为该adr
版本更直接和可读,但adr
伪操作不经常使用,因此人们可能不熟悉它。