Assembly 装配中的重新定位
我有一个用汇编语言编写的裸机手臂的启动代码,我试图理解它是如何工作的。二进制文件写入一些外部闪存中,并在启动时在RAM中复制自身的一部分。尽管我读了这篇文章,但在这种背景下,我仍然没有完全理解搬迁的概念。RAM映射到低地址窗口,闪存映射到高地址窗口。有人能解释一下为什么我们在这里测试链接寄存器的值吗Assembly 装配中的重新定位,assembly,arm,bare-metal,Assembly,Arm,Bare Metal,我有一个用汇编语言编写的裸机手臂的启动代码,我试图理解它是如何工作的。二进制文件写入一些外部闪存中,并在启动时在RAM中复制自身的一部分。尽管我读了这篇文章,但在这种背景下,我仍然没有完全理解搬迁的概念。RAM映射到低地址窗口,闪存映射到高地址窗口。有人能解释一下为什么我们在这里测试链接寄存器的值吗 /* Test if we are running from an address, we are not linked at */ bl check_position check_
/* Test if we are running from an address, we are not linked at */
bl check_position
check_position:
mov r0, lr
ldr r1, =check_position
cmp r0, r1 /* ; don't relocate during debug */
beq relocated_entry
我猜应用程序是从ram运行的,在调试应用程序时,作者可能正在使用某种引导加载程序和/或jtag将测试应用程序直接加载到ram中,因此没有理由复制和运行(这可能会导致崩溃) 您这样做的另一个原因是为了避免无限循环。例如,如果您想从闪存启动(通常必须),但要从ram执行,最简单的方法就是将整个闪存或整个闪存块复制到ram,然后分支到ram的开头。当你这样做的时候,意味着你再次点击“将应用程序复制到ram和分支”循环,为了避免第二次出现(这可能会使你崩溃),你有某种我是否从flash运行这个循环的测试 有人能解释一下为什么我们在这里测试链接寄存器的值吗
/* Test if we are running from an address, we are not linked at */
bl check_position
check_position:
mov r0, lr
ldr r1, =check_position
cmp r0, r1 /* ; don't relocate during debug */
beq relocated_entry
bl check_位置
将把PC+4
的值放在链接寄存器中,并将控制权转移到check_位置
也与PC相关。到目前为止,一切都是相对的
ldr r1,=check_position
从文本池中获取一个值
ldr r1,[pc, #offset]
...
offset:
.long check_position # absolute address from assemble/link.
因此,R0
包含PC相对版本,R1
包含绝对组装版本。这里,对它们进行了比较。您还可以使用算术来计算差异,如果不为零,则进行分支;或者可能将代码复制到其绝对目的地。参考2如果代码在链接地址运行,则R0
和R1
是相同的。这是bl
的一些伪代码
mov lr,pc ; pc is actually two instruction ahead.
add pc,pc,#branch_offset-8
关键是BL
基于PC
执行所有操作,包括更新lr
。我们可以使用movr0,PC
,而不是使用这个技巧,除非PC
前面有8个字节。另一种选择是使用adrr0,检查位置,这将使汇编程序为我们做所有的地址计算
/* 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
参考1:参见gnu汇编程序手册中的和
Ref2:这正是Linuxhead.S
为ARM所做的
编辑:我检查了ARM,PC显然是当前指令+8
,这说明了为什么代码是这样的。我认为adr
版本更直观易读,但是adr
伪op没有经常使用,因此人们可能不熟悉它。感谢您提供了两个非常好的答案!如果可以的话,我会接受这两种方法,因为其中一种解释了代码的目标(JTAG程序加载器假设是正确的),第二种解释了它是如何工作的。对于ARMV6+您可以使用movw r1,#:lower16:check_position
和movt r1,#:upper 16:check_position
而不是ldr r1,=check_position。它可能会跑得稍微快一点。