代碼重定位


1 說明

實驗平台:     JZ2440

CPU:     S3C2440

 

2 S3C2440的啟動過程

圖1 S3C2440A Memory Map after Reset

 

S3C2440支持從多種存儲設備啟動:NOR/NAND Flash, EEPROM, 等等。芯片內部有4K SRAM用於啟動設備使用。至於,設備最終以哪一種方式啟動,通過配置芯片的OM引腳,由芯片內部實現。

 

摘自《S3C2440A_UserManual_Rev13》:

                        圖2 BANK0 BUS WIDTH

 

舉個例子,當選擇以NOR Flash的方式啟動時,芯片的0地址(4K地址空間)會直接映射到Nor Flash上,CPU直接從Nor Flash讀取指令,並執行;當選擇以Nand Flash啟動時,S3C244會把Nand Flash的前4K數據,復制到芯片內部SRAM中,然后CPU從內部SRAM讀取指令,並執行。(NOR Flash 是由內存控制器直接驅動的,而NAND Flash是由NAND Flash控制器驅動的,NAND Flash控制器則由內存控制器驅動,因此NOR Flash是CPU統一編址的,而NAND Flash不是,因此他們間的啟動方式是有區別的)。

 

3 分析可執行文件

*.elf與*.bin文件的區別

bin文件:二進制文件,只包含機器碼;可在機器中直接運行。

elf文件:除了機器碼外,還包含其他額外的信息,例如:段的運行地址,加載地址,重定位表,符號表等等;只能運行於帶操作系統的機器,經操作系統解析(提取出機器碼)后執行;可用於調試。

通過"arm-linux-ld -T target.lds *.o -o *.elf"鏈接得到*.elf文件;然后通過"arm-linux-objcopy -O binary -S *.elf *.bin"把*.elf轉換成*.bin文件。

 

4 鏈接腳本

4.1 程序的組成

程序由代碼段、數據段、只讀數據段、BSS段、注釋段組成,其中BSS段、注釋段不存放於bin文件或elf文件中。

.text:    代碼段;程序中的可執行部分。

.data:    數據段;程序中的全局變量。

.rodata:    只讀數據段;程序中的const類型變量。

.bss:    BSS段;程序中未初始化的或初始值為0的全局變量。

.COMMON:    注釋段。

注意:局部變量是隨着函數的調用,在棧中分配,並在函數退出時釋放。

 

4.2 鏈接腳本說明

當不適用鏈接腳本指示鏈接器進行連接時,鏈接的順序按照Makefile中,文件的放置順序進行鏈接,注意把start.o防置在最前面,否則程序運行會出錯。Makefile中使用鏈接腳本:[-T *.lds]。

 

鏈接腳本的格式:

    SECTIONS{

        secname start Block(align) (NOLOAD) : AT(ldadr)

        {

contents > region : phdr = fill

}

}

 

示例:

圖3 鏈接腳本示例說明

 

注意:鏈接腳本中,每個段的起始地址應當設置為4字節對齊,因為匯編指令會自動把需要操作的地址,自動進行4字節對齊,如果我們對一個非4字節對齊的地址進行操作,會出現意想不到的錯誤。

例如:

    ldr r1, =0x32000000

    ldr r2, =0

    str r2, [r1]

我們期望的結果是,[0x32000000] = 0;但是實際的結果是[0x30000000] = 0;這不是我們想要的。

 

5 代碼重定位

5.1 代碼重定位的意義

從NOR Flash啟動的角度分析:

程序可以直接在NOR Flash上執行。NOR Flash可以通過地址直接讀取,但是不能直接執行寫操作,必須通過特定的操作,才能實現寫操作,因此在NOR Flash上則行程序,其全局變量是無法更改的,因此,我們需要把燒寫到NOR Flash上的程序重新重定位到SDRAM上。

 

從NAND Flash啟動的角度分析:

程序不可以直接在NAND Flash上執行;通過配置OM引腳,當選擇NAND Flash為啟動方式時,芯片內部固件會把NAND Flash的前4K復制到內部SRAM,程序從SRAM的0地址開始執行,當程序超過4K時,為了保證程序能正常運行,一般前4K的代碼實現把程序復制到SDRAM上,然后在SDRAM上執行程序。

 

特別說明:在函數內部聲明一個已初始化的數組,數組的元素是存放於代碼段的;在調用這個函數時,會聲明一個局部變量的指針(數組名),使該指針指向數組元素位於代碼段的首地址,完成初始化動作,因此,未重定位之前,不能使用數組。

 

5.2 重定位的方式

5.2.1 lds文件中的變量

通過對lds文件中的變量進行賦值,在C函數中,通過外部聲明,可以獲取對應段的地址信息。

            圖4

 

實際上,lds文件中的變量,並不會保存在程序中,編譯程序時,有一個符號表(Symbol Table)保存lds中的變量,當程序需要使用lds中的變量時,通過聲明外部變量的方法,通過取值,獲取變量的值。例如:extern int name;target = &name;。

圖5 Symbol Table

 

5.2.2 重定位的方式

只重定位數據段:

程序運行過程中,只有程序中的數據段和BSS段是可能被代碼段修改的,因此在程序運行后,可以只把程序中的數據段以及BSS段重新定位到SDRAM中。

在程序運行中,只需把存放於加載地址的數據段、BSS段,重新定位到運行時地址所指示的位置即可。

 

重定位整個程序:

在程序運行后,把整個程序重新定位到SDRAM中。

 

5.2.3 位置無關碼

b/bl指令是相對跳轉指令,跳轉的目標地址只與當前PC值有關,與運行時地址無關,因此雖然燒寫到NOR Flash上的程序的運行時地址指向SDRAM存儲空間的起始地址(這里是0x30000000),由於b/bl是相對跳轉的,因此,只要在完成重定位操作之前,不涉及全局變量、靜態變量的操作,程序可以正常運行。通過操作相對地址指令實現的代碼,也稱為位置無關碼。

注意,重定位完成后,需要跳轉到C函數去執行程序時,應該使用絕對跳轉(直接修改PC值),而不能使用相對跳轉,否則無法跳到SDRAM上去執行。

 

附錄1 程序源碼

Makefile

 

target.lds

 

Start.S

 

Relocate.c

 

附錄2 參考文檔

《S3C2440用戶手冊》

《The GNU linker》


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM