装配中的重新安置

时间:2013-03-27 23:50:16

标签: assembly arm bare-metal

我有一个用汇编写的裸机ARM的启动代码,我试图了解它是如何工作的。二进制文件写在一些外部Flash中,并在启动时将其自身的一部分复制到RAM中。在这种情况下,我仍然没有完全得到重定位的概念,即使我读过wikipedia entry。 RAM映射到低地址窗口,闪存在高地址窗口中。有人可以向我解释为什么我们在这里测试链接寄存器的值吗?

/* 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 

2 个答案:

答案 0 :(得分:5)

我的猜测是应用程序从ram运行,并且在调试应用程序时,这个作者可能正在使用某种bootloader和/或jtag将测试应用程序直接加载到ram中,因此没有理由复制和运行(这可能会导致崩溃)。

你做这样的事情的另一个原因是避免无限循环。例如,如果您想从闪存(通常必须)启动但是从ram执行,最简单的方法是将整个闪存或整个闪存的一部分复制到ram并且只分支到ram的开头。当你这样做意味着你再次点击“将应用程序复制到ram and branch”循环,以避免它第二次(这可能会让你崩溃),你有一些我从flash运行这个循环或不测试。

答案 1 :(得分:3)

  

有人可以向我解释为什么我们在这里测试链接寄存器的值吗?

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和{ {1}}是一样的。这是R1的一些pseudo code

bl

关键是 mov lr,pc ; pc is actually two instruction ahead. add pc,pc,#branch_offset-8 根据BL执行所有操作,包括PC的更新。我们可以使用lr,而不是使用此技巧,除了mov R0,PC前面是8个字节。另一种方法是使用PC,这将使汇编程序为我们完成所有地址数学运算。

adr R0,check_position

参考1:请参阅gnu-assembler手册中的Arm op-codes.ltorg 参考2:这正是Linux /* 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 正在为ARM做的事情。

编辑:我检查了ARM ARM,而PC显然是当前的指令head.S,这说明了为什么代码是这样的。我认为+8版本更直接,更易读,但adr伪操作不经常使用,所以人们可能不熟悉它。