U-boot-1.1.6 relocate代码详解

这是真正的动手解决自己的疑惑,我把打过100ask_24x0补丁的U-boot-1.1.6的源码进行了反汇编,生成了u-boot.dis文件,然后结合这个文件对start.S的代码中relocate部分进行了分析,这一部分是我一直没搞懂的,憋在心里特别难受,今天反汇编之后一切都豁然开朗了。

1、在正式的说之前还要说两个指令:

参考:http://blog.sina.com.cn/s/blog_4b5210840100c80i.html
https://blog.csdn.net/ray_ree/article/details/48163365
ARM汇编有ldr指令以及ldr、adr伪指令,他门都可以将标号表达式作为操作数,下面通过分析一段代码以及对应的反汇编结果来说明它们的区别。
ldr r0, _start
adr r0, _start
ldr r0, =_start
_start:
b _start

编译的时候设置 RO 为 0x30000000,下面是反汇编的结果:

0x00000000: e59f0004 ldr r0, [pc, #4] ; 0xc
0x00000004: e28f0000 add r0, pc, #0 ; 0x0
0x00000008: e59f0000 ldr r0, [pc, #0] ; 0x10
0x0000000c: eafffffe b 0xc
0x00000010: 3000000c andcc r0, r0, ip
1、adr r0, _start
  这是一条伪指令,总是会被汇编程序汇编为一个指令。汇编程序尝试产生单个 ADD 或 SUB 指令来装载该地址。如果不能在一个指令中构造该地址,则生成一个错误,并且汇编失败。
   在这里是取得标号_start 的地址到 r0,因为地址是相对程序的,因此ADR产生依赖于位置的代码,在此例中被汇编成:add r0, pc, #0。因此该代码可以在和标号相对位置不变的情况下移动;
  假如这段代码在 0x30000000 运行,那么 adr r0, _start 得到 r0 = 0x3000000c;如果在地址 0 运行,就是 0x0000000c 了。
通过这一点可以判断程序在什么地方运行。U-boot中那段relocate代码就是通过adr实现当前程序是在RAM中还是flash中,下面进行简要分析。
这里写图片描述
2、ldr r0, _start
ldr r0, _start是根据_start对当前PC的相对位置读取其所在地址的值,
在这里_start是一个标号(是一个相对程序的表达式),汇编程序计算相对于 PC 的偏移量,并生成相对于 PC的前索引的指令:ldr r0, [pc, #4]。执行指令后,r0 = 0xeafffffe。
3、ldr r0, =_start
  这是一条伪指令,是一个相对程序的或外部的表达式。汇编程序将相对程序的标号表达式 label-expr 的值放在一个文字池中,并生成一个相对程序的 LDR 指令来从文字池中装载该值,在此例中生成的指令为:ldr r0, [pc, #0],对应文字池中的地址以及值为:0x00000010: 3000000c。如果 label-expr 是一个外部表达式,或者未包含于当前段内,则汇编程序在目标文件中放置一个链接程序重定位命令。链接程序在链接时生成地址。
   因此取得的是标号 _start 的绝对地址,这个绝对地址(运行地址)是在连接的时候确定的。它要占用 2 个 32bit 的空间,一条是指令,另一条是文字池中存放_start 的绝对地址。因此可以看出,不管这段代码将来在什么地方运行,它的结果都是 r0 = 0x3000000c。由于ldr r0, =_start取得的是_start的绝对地址,这句代码可以在_start标号的绝对位置不变的情况下移动;如果使用寄存器pc在程序中可以实现绝对转移。

2、下面是u-boot-1.1.6代码中start.S文件的部分内容:

.globl _start
_start: b       reset
    ldr pc, _undefined_instruction
    ldr pc, _software_interrupt
    ldr pc, _prefetch_abort
    ldr pc, _data_abort
    ldr pc, _not_used
    ldr pc, _irq
    ldr pc, _fiq

_undefined_instruction: .word undefined_instruction
_software_interrupt:    .word software_interrupt
_prefetch_abort:    .word prefetch_abort
_data_abort:        .word data_abort
_not_used:      .word not_used
_irq:           .word irq
_fiq:           .word fiq

    .balignl 16,0xdeadbeef


/*
 *************************************************************************
 *
 * Startup Code (reset vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************
 */

_TEXT_BASE:
    .word   TEXT_BASE

.globl _armboot_start
_armboot_start:
    .word _start

/*
 * These are defined in the board-specific linker script.
 */
.globl _bss_start
_bss_start:
    .word __bss_start

.globl _bss_end
_bss_end:
    .word _end

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
    .word   0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
    .word 0x0badc0de
#endif


/*
 * the actual reset code
 */

reset:
    /*
     * set the cpu to SVC32 mode
     */
    mrs r0,cpsr
    bic r0,r0,#0x1f
    orr r0,r0,#0xd3
    msr cpsr,r0

/* turn off the watchdog */
#if defined(CONFIG_S3C2400)
# define pWTCON     0x15300000
# define INTMSK     0x14400008  /* Interupt-Controller base addresses */
# define CLKDIVN    0x14800014  /* clock divisor register */
#elif defined(CONFIG_S3C2410)
# define pWTCON     0x53000000
# define INTMSK     0x4A000008  /* Interupt-Controller base addresses */
# define INTSUBMSK  0x4A00001C
# define CLKDIVN    0x4C000014  /* clock divisor register */
#endif

#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
    ldr     r0, =pWTCON
    mov     r1, #0x0
    str     r1, [r0]

    /*
     * mask all IRQs by setting all bits in the INTMR - default
     */
    mov r1, #0xffffffff
    ldr r0, =INTMSK
    str r1, [r0]
# if defined(CONFIG_S3C2410)
    ldr r1, =0x3ff
    ldr r0, =INTSUBMSK
    str r1, [r0]
# endif

    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr r0, =CLKDIVN
    mov r1, #3
    str r1, [r0]
#endif  /* CONFIG_S3C2400 || CONFIG_S3C2410 */

    /*
     * we do sys-critical inits only at reboot,
     * not when booting from ram!
     */
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
    bl  cpu_init_crit
#endif

#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate:               /* relocate U-Boot to RAM       */
    adr r0, _start      /* r0 <- current position of code , r0 = 取_start实际运行时的地址 */
    ldr r1, _TEXT_BASE      /* test if we run from flash or RAM, r1 = 33f80000(链接地址) */
    cmp     r0, r1                  /* don't reloc during debug         */
    beq     stack_setup

    ldr r2, _armboot_start  /*此时的r2寄存器中的内容 就是程序实际运行时的起始地址 _start*/
    ldr r3, _bss_start   /*此时的r3寄存器中的内容 就是按照链接脚本指定的排放规则,从实际运行地址
                         排放到_bss_start,所以我认为此时的r3的大小应该是和程序实际地址相关的*/
    sub r2, r3, r2      /* r2 <- size of armboot            */
    add r2, r0, r2      /* r2 <- source end address         */

copy_loop:
    ldmia   r0!, {r3-r10}       /* copy from source address [r0]    */
    stmia   r1!, {r3-r10}       /* copy to   target address [r1]    */
    cmp r0, r2          /* until source end addreee [r2]    */
    ble copy_loop
#endif  /* CONFIG_SKIP_RELOCATE_UBOOT */

    /* Set up the stack                         */
stack_setup:
    ldr r0, _TEXT_BASE      /* upper 128 KiB: relocated uboot   */
    sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */
    sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
    sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
    sub sp, r0, #12     /* leave 3 words for abort-stack    */

clear_bss:
    ldr r0, _bss_start      /* find start of bss segment        */
    ldr r1, _bss_end        /* stop here                        */
    mov     r2, #0x00000000     /* clear                            */

clbss_l:str r2, [r0]        /* clear loop...                    */
    add r0, r0, #4
    cmp r0, r1
    ble clbss_l

#if 0   /*条件编译,这段内容不会被编译,当然,在下面的反汇编文件中也就不会存在*/
    /* try doing this stuff after the relocation */
    ldr     r0, =pWTCON
    mov     r1, #0x0
    str     r1, [r0]

    /*
     * mask all IRQs by setting all bits in the INTMR - default
     */
    mov r1, #0xffffffff
    ldr r0, =INTMR
    str r1, [r0]

    /* FCLK:HCLK:PCLK = 1:2:4 */
    /* default FCLK is 120 MHz ! */
    ldr r0, =CLKDIVN
    mov r1, #3
    str r1, [r0]
    /* END stuff after relocation */
#endif

    ldr pc, _start_armboot

_start_armboot: .word start_armboot


/*
 *************************************************************************
 *
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************
 */


#ifndef CONFIG_SKIP_LOWLEVEL_INIT
cpu_init_crit:
    /*
     * flush v4 I/D caches
     */
    mov r0, #0
    mcr p15, 0, r0, c7, c7, 0   /* flush v3/v4 cache */
    mcr p15, 0, r0, c8, c7, 0   /* flush v4 TLB */

    /*
     * disable MMU stuff and caches
     */
    mrc p15, 0, r0, c1, c0, 0
    bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
    bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
    orr r0, r0, #0x00000002 @ set bit 2 (A) Align
    orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
    mcr p15, 0, r0, c1, c0, 0

    /*
     * before relocating, we have to setup RAM timing
     * because memory timing is board-dependend, you will
     * find a lowlevel_init.S in your board directory.
     */
    mov ip, lr
    bl  lowlevel_init
    mov lr, ip
    mov pc, lr
#endif /* CONFIG_SKIP_LOWLEVEL_INIT */

u-boot-1.1.6的makefile在实际编译的时候大概执行了这么一条语句:
arm-linux-ld -Bstatic -T u-boot.lds -Ttext 0x33F80000 start.o …

3、这是start.S反汇编之后的内容

u-boot:     file format elf32-littlearm

Disassembly of section .text:

33f80000 <_start>:
33f80000:   ea000012    b   33f80050 <reset>
33f80004:   e59ff014    ldr pc, [pc, #20]   ; 33f80020 <_undefined_instruction>
33f80008:   e59ff014    ldr pc, [pc, #20]   ; 33f80024 <_software_interrupt>
33f8000c:   e59ff014    ldr pc, [pc, #20]   ; 33f80028 <_prefetch_abort>
33f80010:   e59ff014    ldr pc, [pc, #20]   ; 33f8002c <_data_abort>
33f80014:   e59ff014    ldr pc, [pc, #20]   ; 33f80030 <_not_used>
33f80018:   e59ff014    ldr pc, [pc, #20]   ; 33f80034 <_irq>
33f8001c:   e59ff014    ldr pc, [pc, #20]   ; 33f80038 <_fiq>

33f80020 <_undefined_instruction>:
33f80020:   33f80140    mvnccs  r0, #16 ; 0x10

33f80024 <_software_interrupt>:
33f80024:   33f801a0    mvnccs  r0, #40 ; 0x28

33f80028 <_prefetch_abort>:
33f80028:   33f80200    mvnccs  r0, #0  ; 0x0

33f8002c <_data_abort>:
33f8002c:   33f80260    mvnccs  r0, #6  ; 0x6

33f80030 <_not_used>:
33f80030:   33f802c0    mvnccs  r0, #12 ; 0xc

33f80034 <_irq>:
33f80034:   33f80320    mvnccs  r0, #-2147483648    ; 0x80000000

33f80038 <_fiq>:
33f80038:   33f80380    mvnccs  r0, #2  ; 0x2
33f8003c:   deadbeef    cdple   14, 10, cr11, cr13, cr15, {7}

33f80040 <_TEXT_BASE>:
33f80040:   33f80000    mvnccs  r0, #0  ; 0x0

33f80044 <_armboot_start>:
33f80044:   33f80000    mvnccs  r0, #0  ; 0x0

33f80048 <_bss_start>:
33f80048:   33fa4c00    mvnccs  r4, #0  ; 0x0

33f8004c <_bss_end>:
33f8004c:   33fa9f04    mvnccs  r9, #16 ; 0x10

33f80050 <reset>:
33f80050:   e10f0000    mrs r0, CPSR
33f80054:   e3c0001f    bic r0, r0, #31 ; 0x1f
33f80058:   e38000d3    orr r0, r0, #211    ; 0xd3
33f8005c:   e129f000    msr CPSR_fc, r0
33f80060:   e3a00453    mov r0, #1392508928 ; 0x53000000
33f80064:   e3a01000    mov r1, #0  ; 0x0
33f80068:   e5801000    str r1, [r0]
33f8006c:   e3e01000    mvn r1, #0  ; 0x0
33f80070:   e59f0360    ldr r0, [pc, #864]  ; 33f803d8 <.text+0x3d8>
33f80074:   e5801000    str r1, [r0]
33f80078:   e59f135c    ldr r1, [pc, #860]  ; 33f803dc <.text+0x3dc>
33f8007c:   e59f035c    ldr r0, [pc, #860]  ; 33f803e0 <.text+0x3e0>
33f80080:   e5801000    str r1, [r0]
33f80084:   e59f0358    ldr r0, [pc, #856]  ; 33f803e4 <.text+0x3e4>
33f80088:   e3a01003    mov r1, #3  ; 0x3
33f8008c:   e5801000    str r1, [r0]
33f80090:   eb000018    bl  33f800f8 <cpu_init_crit>

33f80094 <relocate>:
33f80094:   e24f009c    sub r0, pc, #156    ; 0x9c  /*33f80094(hex)+8-156(dec)=33f80000(hex)*/
33f80098:   e51f1060    ldr r1, [pc, #-96]  ; 33f80040 <_TEXT_BASE> /*r1=[33f80098+8-96(dec)]=[33f80040] = 33f80000*/
33f8009c:   e1500001    cmp r0, r1
33f800a0:   0a000007    beq 33f800c4 <stack_setup>
33f800a4:   e51f2068    ldr r2, [pc, #-104] ; 33f80044 <_armboot_start>
33f800a8:   e51f3068    ldr r3, [pc, #-104] ; 33f80048 <_bss_start>
33f800ac:   e0432002    sub r2, r3, r2
33f800b0:   e0802002    add r2, r0, r2

33f800b4 <copy_loop>:
33f800b4:   e8b007f8    ldmia   r0!, {r3, r4, r5, r6, r7, r8, r9, sl}
33f800b8:   e8a107f8    stmia   r1!, {r3, r4, r5, r6, r7, r8, r9, sl}
33f800bc:   e1500002    cmp r0, r2
33f800c0:   dafffffb    ble 33f800b4 <copy_loop>

33f800c4 <stack_setup>:
33f800c4:   e51f008c    ldr r0, [pc, #-140] ; 33f80040 <_TEXT_BASE>
33f800c8:   e2400803    sub r0, r0, #196608 ; 0x30000
33f800cc:   e2400080    sub r0, r0, #128    ; 0x80
33f800d0:   e240d00c    sub sp, r0, #12 ; 0xc

33f800d4 <clear_bss>:
33f800d4:   e51f0094    ldr r0, [pc, #-148] ; 33f80048 <_bss_start>
33f800d8:   e51f1094    ldr r1, [pc, #-148] ; 33f8004c <_bss_end>
33f800dc:   e3a02000    mov r2, #0  ; 0x0

33f800e0 <clbss_l>:
33f800e0:   e5802000    str r2, [r0]
33f800e4:   e2800004    add r0, r0, #4  ; 0x4
33f800e8:   e1500001    cmp r0, r1
33f800ec:   dafffffb    ble 33f800e0 <clbss_l>
33f800f0:   e51ff004    ldr pc, [pc, #-4]   ; 33f800f4 <_start_armboot>

33f800f4 <_start_armboot>:
33f800f4:   33f80cbc    mvnccs  r0, #48128  ; 0xbc00

33f800f8 <cpu_init_crit>:
33f800f8:   e3a00000    mov r0, #0  ; 0x0
33f800fc:   ee070f17    mcr 15, 0, r0, cr7, cr7, {0}
33f80100:   ee080f17    mcr 15, 0, r0, cr8, cr7, {0}
33f80104:   ee110f10    mrc 15, 0, r0, cr1, cr0, {0}
33f80108:   e3c00c23    bic r0, r0, #8960   ; 0x2300
33f8010c:   e3c00087    bic r0, r0, #135    ; 0x87
33f80110:   e3800002    orr r0, r0, #2  ; 0x2
33f80114:   e3800a01    orr r0, r0, #4096   ; 0x1000
33f80118:   ee010f10    mcr 15, 0, r0, cr1, cr0, {0}
33f8011c:   e1a0c00e    mov ip, lr
33f80120:   eb0000b7    bl  33f80404 <lowlevel_init>
33f80124:   e1a0e00c    mov lr, ip
33f80128:   e1a0f00e    mov pc, lr
    ...

猜你喜欢

转载自blog.csdn.net/baidu_35679960/article/details/81331761