这是真正的动手解决自己的疑惑,我把打过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
...