在start.s中有如下定義
.globl _start (start.s的第一條語句)
………
_TEXT_BASE:
.word TEXT_BASE
.word表示在當前地址保存TEXT_BASE這個值,TEXT_BASE在config.mk中定義,它的值爲0x33D00000,_TEXT_BASE是這個地址的標號,我們可以通過這個標號找到這個地址,在編譯之後它纔有具體的值。
下面是relocate部分的彙編程序,這段程序的作用是判斷程序當前運行的位置(在內部RAM還是在SDRAM中),在debug的時候uboot是直接在SDRAM中運行的,所以就沒有必要拷貝了。也就是說,這段程序是判斷uboot是正常運行還是在debug狀態下運行。
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq clear_bss/*相等則跳過拷貝部分的代碼*/
/*不相等則執行以下代碼,調用C函數CopyCode2Ram的時候r0,r1,r2用於傳遞參數*/
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
bl CopyCode2Ram /* r0: source, r1: dest, r2: size */
adr r0, _start
adr是位置無關指令,它取得的時相對的位置。例如這段代碼在 0x33d00000 運行,那麼 adr r0, _start 得到 r0 = 0x33d00000 ;如果在地址 0 運行,就是 0x00000000 了。
也就是說如果uboot是開發板上電後啓動的,那麼執行這條指令後r0的值就是0x00000000 ,如果uboot是用jlink等工具debug的,那麼執行這條指令後r0的值就是0x33D00000
ldr r1, _TEXT_BASE
ldr指令把_TEXT_BASE這個地址處的值賦給r1(注意跟ldr僞指令區分開來ldr r0, =_TEXT_BASE,這條指令是把_TEXT_BASE的絕對地址賦給r1),這條指令執行完後r1的值爲0x33D00000
cmp r0, r1
比較r0和r1,如果相等則說明是處於debug狀態,uboot已經處於SDRAM中了,沒必要再拷貝;不相等則說明uboot還處於內部RAM中,需要拷貝。
下面是對應的反彙編代碼:
33d000b0 <relocate>:
33d000b0: e24f00b8 sub r0, pc, #184 ; 0xb8
;非debug狀態下pc的值爲0x000000b8(pc指向當前指令的下兩條指令),r0=0x000000b8-0xb8=0x00000000
33d000b4: e51f107c ldr r1, [pc, #-124] ; 33d00040 <_TEXT_BASE>
;pc的值爲0x000000bc,也就是ldr r1,[0x40],0x40處存放的值爲0x33d00000,所以r1=0x33d00000
33d000b8: e1500001 cmp r0, r1
33d000bc: 0a000003 beq 33d000d0 <clear_bss>
33d000c0: e51f2084 ldr r2, [pc, #-132] ; 33d00044 <_armboot_start>
33d000c4: e51f3084 ldr r3, [pc, #-132] ; 33d00048 <_bss_start>
33d000c8: e0432002 sub r2, r3, r2
33d000cc: eb00020a bl 33d008fc <CopyCode2Ram>
最後由彙編跳轉到C是通過執行下面的語句實現的:
ldr pc, _start_armboot
_start_armboot: .word start_armboot
其中start_armboot是c函數名,改函數的地址存放在_start_armboot這個地址處,ldr pc, _start_armboot通過把_start_armboot這個地址裏面存放的值賦給pc,實現跳轉。