什么是重定位?為什么要代碼重定位?
要弄清楚上面的這兩個問題,首先要理解下面這幾個概念
一、編碼
(1)位置無關編碼:PIC,可執行程序運行時與代碼在內存中的地址無關,代碼中沒有使用絕對地址,而是使用的相對地址。(例如:B、BL、MOV等指令)
(2)位置有關編碼:可執行程序運行時與代碼在內存中的地址有關系。(例如:LDR PC, =MAIN等指令)
二、地址
(1)鏈接地址:程序編譯鏈接時指定的地址(使用makefile或者鏈接腳本可以指定鏈接地址)
(2)運行地址:程序在內存中實際運行的地址。
三、S5PV210的啟動
在uboot中的啟動方式,將整個uboot分為2個部分(BL1和BL2),是分別加載到內存中去運行的。在這個過程中,程序的鏈接地址和運行地址就很可能不是相同的了,但是在代碼中又有一些位置有關碼,為了使得程序可以正常的運行,就必須使用重定位來解決。(關於S5PV210的啟動在另一篇文章里有介紹)
四、如何重定位?
1、鏈接腳本指定鏈接地址
2、判斷運行地址和鏈接地址是否相同
3、復制代碼到指定的鏈接地址處,使用長轉移指令進行跳轉
具體的實現如下:
【鏈接腳本代碼】
1 SECTIONS 2 { 3 . = 0xd0024000; 4 5 .text : { 6 start.o 7 * (.text) 8 } 9 10 .data : { 11 *(.data) 12 } 13 14 bss_start = .; 15 .bss : { 16 * (.bss) 17 } 18 19 bss_end = .; 20 }
【重定位代碼】
adr r0, _start // 短加載,獲取_start的運行地址 ldr r1, =_start // 長加載,獲取_start的鏈接地址 ldr r2, =bss_start // 獲取bss鏈接地址,重定位代碼的結束地址 cmp r0, r1 // 比較_start的運行地址和鏈接地址是否相等 beq clean_bss // 相等:不需要重定位;跳轉到clean_bss // 不相等:需要重定位;繼續往下執行 // 匯編實現while完成代碼賦值到重定位地址 copy_loop: ldr r3, [r0], #4 // 源 str r3, [r1], #4 // 目的 先把r3中的內容放入r1的指向的地址; cmp r1, r2 // 然后r1 =r1 + 4 bne copy_loop