(1)代码及注释
.globl _start /*声明一个符号可被其它文件引用,相当于声明了一个全局变量,
.globl与.global相同*/
_start: b reset /* b是不带返回的跳转(bl是带返回的跳转),
意思是无条件直接跳转到reset标号处执行程序*/
ldr pc, _undefined_instruction /*未定义指令异常向量,ldr的作用是,
将符号_undefined_instruction指向的地址的内容加载到pc*/
ldr pc, _software_interrupt /*软件中断向量*/
ldr pc, _prefetch_abort /*预取指令异常向量*/
ldr pc, _data_abort /*数据操作异常向量*/
ldr pc, _not_used /*未使用*/
ldr pc, _irq /*irq中断向量*/
ldr pc, _fiq /*fiq中断向量*/
#ifdef CONFIG_SPL_BUILD //我的uboot中没有定义这个宏,关于这个宏的介绍,请看下文
_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
_pad: .word 0x12345678 /* now 16*4=64 */
#else
.globl _undefined_instruction
_undefined_instruction: .word undefined_instruction /*就是在当前地址,即
_undefined_instruction 处存放 undefined_instruction。
通过下面的反汇编代码可以看到,这个地址存放的内容是0x87800120*/
.globl _software_interrupt
_software_interrupt: .word software_interrupt
.globl _prefetch_abort
_prefetch_abort: .word prefetch_abort
.globl _data_abort
_data_abort: .word data_abort
.globl _not_used
_not_used: .word not_used
.globl _irq
_irq: .word irq
.globl _fiq
_fiq: .word fiq
_pad: .word 0x12345678 /* now 16*4=64 */
#endif /* CONFIG_SPL_BUILD */
.global _end_vect
_end_vect:
.balignl 16,0xdeadbeef /*这句代码使下面的代码开始处16字节对齐,
即当上段的代码运行完后不是16字节对齐,就填充0xdeadbeef,直到使下段
的代码开始处16字节对齐。*/
/*************************************************************************
*
* Startup Code (reset vector)
*
* do important init only if we don't start from memory!
* setup Memory and board specific bits prior to relocation.
* relocate armboot to ram
* setup stack
*
*************************************************************************/
/*************************************************
下面是IRQ中断,放了一个IRQ_STACK_START标号,标号内容为:0x0badc0de,
此内容没有意义,只是为了占一个坑。程序刚刚运行,还没有进入初始化,根本不知
道堆栈指针现在应该放在什么地方,所以一开始,作者做了一个小技巧,填充一个无
效的数字,等初始化以后堆栈指针建立好后,再将实际的堆栈指针写到这里。然而在
我的平台里CONFIG_USE_IRQ这个宏并没有定义!!!
*************************************************/
#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
/* IRQ stack memory (calculated at run-time) + 8 bytes */
/*下面也是不能确定堆栈指针地址,所以填充无效数字,当堆栈指针确定以后,将其加8填充到这里*/
.globl IRQ_STACK_START_IN
IRQ_STACK_START_IN:
.word 0x0badc0de
(2)反汇编代码
为了更好的理解上面用到的汇编指令,对uboot进行反汇编。使用命令:
arm-fsl-linux-gnueabi-objdump -D u-boot > u-boot.s
uboot.s就是反汇编出来的文件,以上这段代码对应的反汇编代码如下:
u-boot: file format elf32-littlearm
Disassembly of section .text:
87800000 <__image_copy_start>:
87800000: ea00000f b 87800044 <reset>
87800004: e59ff014 ldr pc, [pc, #20] ; 87800020 <_undefined_instruction>
87800008: e59ff014 ldr pc, [pc, #20] ; 87800024 <_software_interrupt>
8780000c: e59ff014 ldr pc, [pc, #20] ; 87800028 <_prefetch_abort>
87800010: e59ff014 ldr pc, [pc, #20] ; 8780002c <_data_abort>
87800014: e59ff014 ldr pc, [pc, #20] ; 87800030 <_not_used>
87800018: e59ff014 ldr pc, [pc, #20] ; 87800034 <_irq>
8780001c: e59ff014 ldr pc, [pc, #20] ; 87800038 <_fiq>
87800020 <_undefined_instruction>:
87800020: 87800120 strhi r0, [r0, r0, lsr #2]
87800024 <_software_interrupt>:
87800024: 87800180 strhi r0, [r0, r0, lsl #3]
87800028 <_prefetch_abort>:
87800028: 878001e0 strhi r0, [r0, r0, ror #3]
8780002c <_data_abort>:
8780002c: 87800240 strhi r0, [r0, r0, asr #4]
87800030 <_not_used>:
87800030: 878002a0 strhi r0, [r0, r0, lsr #5]
87800034 <_irq>:
87800034: 87800300 strhi r0, [r0, r0, lsl #6]
87800038 <_fiq>:
87800038: 87800360 strhi r0, [r0, r0, ror #6]
8780003c <_pad>:
8780003c: 12345678 eorsne r5, r4, #125829120 ; 0x7800000
87800040 <IRQ_STACK_START_IN>:
87800040: 0badc0de bleq 863703c0 <__image_copy_start-0x148fc40>
请看语句:ldr pc, [pc, #20] ; 87800020 <_undefined_instruction>
,当要跳转到_undefined_instruction时,为什么是将当前pc的值加20后再赋给pc呢?
流水线操作:取址—>译码—>运行;
把内存中的代码取到CPU中,把e59ff014翻译成对应的命令,ldr pc,[pc,#20],然后运行。所以pc指针并不是指向当前运行的命令,而是指向当前运行的指令加8,加8超前两个指令,一个用来取址,一个用来译码,即:
pc=0x87800004+0x08=0x8780000c, pc= 0x8780000c+0x14(即20)=0x87800020
即把0x87800020地址处的数字0x87800120放到pc指针里面,即直接跳转到0x87800120地址处运行。
(3) CONFIG_SPL_BUILD介绍
这个宏定义的主要作用就是生成 BL1 文件,提到 BL1 文件肯定又会有朋友产生疑问,在这里就这个 BL1 文件给大家简单的介绍一下:
BL1 文件是一段外部代码,存放在 SD 卡或者 nandflash 上,大小为(4K\8K\16K)。除了 BL1 文件,还有 BL0 和 BL2 文件。BL0 文件是存放在 CPU 内部 IROM 中的一段固化代码,CPU 上点之后,首先去运行BL0 文件。BL2 文件是完整的 U-Boot 代码。
这三个文件之间的关系就是:BL0 运行时会将 BL1 拷贝到 CPU 的 IRAM 中,然后执行BL1,BL1 文件执行起来之后会先进行内存的初始化,之后将 BL2 文件拷贝到外部内存中运行。