首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在这里,u-boot的迁移是如何工作的?

在这里,u-boot的迁移是如何工作的?
EN

Stack Overflow用户
提问于 2013-10-21 15:05:59
回答 1查看 1.6K关注 0票数 0

我正在尝试理解代码的一部分,其中表示它在RAM中重新启动U-boot,下面是代码。

代码语言:javascript
复制
   #ifndef  CONFIG_SKIP_RELOCATE_UBOOT
   relocate:
     adr r0,_start      /*r0 <--- Current posistion of code8*/
     ldr r1,_TEXT_BASE  /* test if we run from flash or Ram /*
     cmp r0,r1
     beq stack_setup
     ldr r2,_armboot_start   
     ldr r3,_bss_start
     sub r2,r3,r2
     add r2,r0,r2
   copy_loop:
     ldmia r0!,{r3-r10}
     stmia r1!,{r3-r10}
     cmp   r0,r2
     ble   cop_loop
     #endif /*CONFIG_SKIP_RELOCATE_UBOOT/*

现在,canbody让我知道它是如何在这里发生的??我们是如何测试我们的u引导是从RAM还是Flash运行的?

我在手臂平台上。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-21 16:55:47

下面是一个非常简单的例子,

代码语言:javascript
复制
.globl _start
_start:

    adr r0,_start
    ldr r1,_TEXT_BASE

...

_TEXT_BASE: .word _start

在组装、连接和拆卸时:

代码语言:javascript
复制
00008000 <_start>:
    8000:   e24f0008    sub r0, pc, #8
    8004:   e59f101c    ldr r1, [pc, #28]   ; 8028 <_TEXT_BASE>
...
00008028 <_TEXT_BASE>:
    8028:   00008000    andeq   r8, r0, r0

这就是你的答案。adr指令基于假设您的pc在执行时包含0x8008。无论您在哪里,ldr都会拉出一个链接时间值,这是相同的。

例如,如果该代码实际上位于地址0x20000000,那么当第一条指令( adr是伪指令,反汇编中是8的一个子指令)执行adr时,就会得到0x200008-8= 0x20000000,并将其与0x8000进行比较,它们不匹配。如果您在0x8000运行代码,那么0x8008-8 = 0x8000和两个匹配。

只需阅读代码并查找adr指令(或执行我所做的操作,并尝试它并检查编译器/工具的输出,如果没有显示答案,则在硬件上运行它)。

编辑:

使用具有各种前缀的gnu,但是这段代码非常简单,根本不在乎。手臂-无-eabi-或臂-无-linux-gnueabi-。

假设程序集文件名为foo.s

代码语言:javascript
复制
arm-none-eabi-as foo.s -o foo.o
arm-none-eabi-ld -T memmap foo.o -o foo.elf
arm-none-eabi-objdump -D foo.elf

我称之为memmap的是链接器脚本,在本例中可以使用命令行-Ttext=0x8000。我喜欢在交叉编译二进制文件中使用.elf扩展,不是每个人都这么做的。

代码语言:javascript
复制
00008000 <_start>:
    8000:   e24f0008    sub r0, pc, #8
    8004:   e59f101c    ldr r1, [pc, #28]   ; 8028 <_TEXT_BASE>
...
00008028 <_TEXT_BASE>:
    8028:   00008000    andeq   r8, r0, r0

_start是一个gnu,链接器需要/希望这个标签知道代码的入口点在哪里。因此,它并不是一个真正的uboot的事情,虽然uboot可能也关心,但它肯定是一个gnu链接的事情。

对于以ARM为基础的linux程序来说,0x8000是一个常见的地址,它是一个入口点,您将看到linux作为一个内核从这样的地址开始,但是它确实是任意的,您可以为任何东西设置您的系统和二进制文件。

这里所发生的一切并没有什么特别的或神奇的东西。在任何平台上都有相同的想法,你只需想出正确的说明。

arm中的程序计数器是前面的两条指令,这是32位arm指令,因此在执行指令时程序计数器被假定为该指令加8的地址。因为这个adr是_start上的第一条指令,这意味着该指令在地址0x8000作为链接/编译,因此从0x8008到0x8000,指令被编码为r0 = pc-8;其他信息是链接器在标签_TEXT_BASE之后为_start提供地址。因此,另一个步骤是将该值加载到r1中。

只有在这样的假设和事实下才能工作,即代码实际上生活在一个闪存中,以至于处理器在地址0x8000的闪存中看到了该指令。0x8000和0x8000的比较是相等的,所以程序会在ram中复制自己,然后跳转到这个副本所在的位置,这一次当它通过代码副本时,一个寄存器包含一些地址而不是0x8000,所以比较失败,如果您从闪存运行原始版本或从ram运行副本,这只是一个检测器。其目的是复制并运行基于ram的副本。还需要采取其他预防措施,以确保代码可以在两个地址(位置独立代码)上运行。

如果您碰巧知道闪存地址为0x00008000,并且碰巧知道内存地址为0x20000000,则可以将pc与比如说0x10000进行比较,或者可以将pc的值与0xFF000000进行比较。

代码语言:javascript
复制
and r0,pc,#0xFF000000
beq stack_setup

但我假设这是更通用的代码,所以使用额外的指令和精确的比较。

同样,这种技巧是相当常见的,检测闪存或ram副本,等等,使用的确切说明,以及如何让链接器为您填写的东西是特定于目标。

在这种情况下,闪存可能位于某个非零地址,而0x8000是ram副本。我不知道。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19498118

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档