uboot中start.S相關代碼分析
重定位
——即把falsh中的代碼複製到ram(sdram)中,本開發板複製到sdram中。
不管我們開發板是以什麼方式啓動(nor/nand)啓動,都需要進行重定位
因爲:
當nor啓動時,因爲nor的特性,只能讀不能寫,因此需要從定位,
當nand啓動時,nand啓動只把前4k代碼複製到片內內存,uboot打印4k,因此需要重定位。相應繼續執行4K以後的代碼,就必須重定位,然後跳到重定位後的地址執行。
代碼分析
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 stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
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
/*這段代碼是在start.S最開頭*/
.globl _start
_start: b reset
解析:
1、ADR僞指令— 小範圍的地址讀取
ADR僞指令將基於PC相對偏移的地址值或基於寄存器相對偏移的地址值讀取到寄
存器中。
在彙編編譯器編譯源程序時,ADR僞指令被編譯器替換成一條合適的指令。通
常,編譯器用一條ADD指令或SUB指令來實現該ADR僞指令的功能,若不能用一
條指令實現,則產生錯誤,編譯失敗。
- adr r0, _start的意思其實很簡單,就是將_start(這個是代碼最開始執行的)的地址賦值給r0.但是具體實現的方式就有點複雜了,對於用adr指令實現的話,說明_start這個地址,相對當前PC的偏移,應該是很小的,意思就是向前一段後者向後一段去找,肯定能找到_start這個標號地址的,此處,自己通過看代碼也可以看到_start,就是在當前指令的前面,距離很近,編譯後,對應彙編代碼,也可以猜得出,應該是上面所說的,用sub來實現,即當前PC減去某個值,得到_start的值(在從Nor Flash啓動時,對應的代碼,也是在Nor Flash中,對應的物理地址是0x0,如果直接從鏈接地址運行時,該值就是鏈接地址),此時是0x0。
- cmp r0, r1 因此r0不等r1,beq不成立,所以不跳到stack_setup執行。
- ldr r2, _armboot_start //_armboot_start這個標號中的值_start賦給r2,實際就是鏈接地址
ldr r3, _bss_start //根據鏈接腳本可知這是代碼段的結束地址,bss段的起始地址
sub r2, r3, r2 /計算出uboot的大小 /
add r2, r0, r2 /重定位的結束地址 / - 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
這就是循環的進行代碼得複製