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》