2013-03-27 62 views
5

我有一个在程序集中编写的裸机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 
+0

谢谢你的两个很好的答案!我会接受这两个,因为我解释了代码的目标(JTAG程序加载器的假设是正确的),第二个是如何工作的。 – 2013-03-28 14:50:37

回答

5

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

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

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如果代码是运行连接的地址,那么R0R1是相同的。这是bl的一些pseudo code

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 

Ref1至:Arm op-codes.ltorg在GNU汇编手册
至Ref2:这正是Linux的head.S做了ARM。

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