6

我有一个用汇编语言编写的裸机 ARM 的启动代码,我试图了解它是如何工作的。该二进制文件被写入一些外部闪存中,并在启动时将其自身的一部分复制到 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 
4

2 回答 2

5

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

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

于 2013-03-28T00:03:00.110 回答
4

谁能向我解释为什么我们在这里测试链接寄存器的值?

将把的bl check_positionPC+4放在链接寄存器中,并将控制权转移给check_positionPC 相关人员。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 如果代码在链接地址运行,则和是相同的。这是一些针对.R0R1pseudo codebl

 mov lr,pc               ; pc is actually two instruction ahead.
 add pc,pc,#branch_offset-8

关键是一切都BL基于. 除了提前 8 个字节之外,我们可以使用,而不是使用这个技巧。另一种选择是使用,这将使汇编程序为我们完成所有地址数学运算。PClrmov R0,PCPCadr 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伪操作不经常使用,因此人们可能不熟悉它。

于 2013-03-28T00:20:41.300 回答