【问题标题】:Relocation in assembly装配中的搬迁
【发布时间】:2013-03-18 07:02:45
【问题描述】:

我有一个用汇编语言编写的裸机 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 

【问题讨论】:

  • 感谢您的两个出色回答!如果我能做到,我会接受这两个,因为一个解释了代码的目标(JTAG 程序加载器假设是正确的),第二个解释了它是如何工作的。

标签: assembly arm bare-metal


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    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 包含绝对组装版本。在这里,它们进行了比较。您还可以使用算术计算差异,然后如果非零,则 branch 到它;或者可能将代码复制到它的绝对目的地。Ref2 如果代码在链接地址运行,则R0R1是相同的。这是pseudo code 的一些bl

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

    关键是BL 所做的一切都基于PC,包括lr 的更新。我们可以使用mov R0,PC,而不是使用这个技巧,除了PC 提前8 个字节。另一种选择是使用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: 这正是 Linux head.S 正在为ARM。

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

    【讨论】:

      猜你喜欢
      • 2015-05-07
      • 2011-10-28
      • 2012-04-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-04-29
      • 1970-01-01
      相关资源
      最近更新 更多