劉浩
(青島職業(yè)技術學院信息學院,青島 266555)
使用μ Vision進行ARM嵌入式軟件開發(fā)的工程師,在閱讀μ Vision自動生成的引導代碼之后會發(fā)現(xiàn)它并沒有直接調(diào)用main函數(shù),而是調(diào)用了一個奇怪的__main函數(shù),并且手冊中沒有相關的解釋。雖然表面上看起來這并不是什么大問題,但是實際上這里面蘊含著一些重要的概念,例如映像結構、分散加載機制和重定位等。掌握了這些概念之后,可以更好地理解系統(tǒng)初始化過程。由于__main函數(shù)位于ARM C庫中,沒有提供源代碼,為此本文通過反匯編的方法從源代碼級別詳細地闡述了__main函數(shù)的功能:復制重定位區(qū)、初始化ZI節(jié),以及初始化堆棧和堆等。示例工程getting-started-project-at91sam9261-ek運行在Atmel公司的AT91SAM9261-EK評估板上,集成開發(fā)環(huán)境為 Keil公司的 μ Vision3.62c,配置使用 Real-View工具鏈。
C語言源文件至少經(jīng)過預處理、編譯和鏈接3個階段,才能生成最終的可執(zhí)行映像文件。在預處理階段,預處理器對源文件進行頭文件和宏替換。編譯與鏈接過程如圖1所示。在編譯階段,編譯器分別對各個源文件進行編譯生成對應的對象文件。在鏈接階段,編譯階段生成的對象文件、其他庫和分散加載文件一起作為鏈接器的輸入,生成最終的可執(zhí)行文件,同時生成的還有鏈接地址映射文件,它包含了關于映像的節(jié)、符號表和存儲器映射等信息。
圖1 編譯與鏈接過程
在嵌入式系統(tǒng)中,為了最大限度地提高系統(tǒng)效率,通常需要將一些關鍵代碼(例如異常處理器)和頻繁訪問的數(shù)據(jù)(例如異常向量)定位到訪問速度較快的存儲器中。RealView工具鏈使用分散加載機制來創(chuàng)建具有復雜存儲器映射的映像。下面的分散加載文件sdram.sct是為了在外部SDRAM中調(diào)試程序而編寫的。
分散加載文件用來描述代碼和數(shù)據(jù)加載時和執(zhí)行時應在的位置。以sdram.sct為例,它定義了1個加載區(qū)和4個執(zhí)行區(qū)。應用程序的映像文件存儲在起始地址為0x20000000的加載區(qū)Load_region中。加載視圖和執(zhí)行視圖如圖2所示。系統(tǒng)上電后,除了異常向量VECTOR需要重定位到起始地址為0x00300000的片內(nèi)SRAM以外,其余的代碼和數(shù)據(jù)的地址保持不變。也就是說,符號的加載地址和執(zhí)行地址并不是完全匹配的,例如VECTOR的加載地址為0x20001da4而執(zhí)行地址為0x00300000,而且在加載視圖中根本不存在堆、堆棧和ZI節(jié)。但是從加載視圖到執(zhí)行視圖的轉換并不是自動完成的,這部分代碼位于庫函數(shù)__main中,它主要負責將VECTOR從Load_region區(qū)移動到Relocate_region區(qū),初始化ZI區(qū)、堆和堆棧,最后調(diào)用main函數(shù)。
圖2 加載視圖和執(zhí)行視圖
鏈接器armlink在生成可執(zhí)行文件的同時,還會生成一個鏈接地址映射文件at91sam9261-sdram.map。它包含了映像文件的各種信息,例如交叉引用、符號鏈接地址,以及加載區(qū)和執(zhí)行區(qū)的基址、大小和內(nèi)容等。表1和表2列出了一些__main函數(shù)中需要使用的重要信息,對照圖2可以更加清楚地理解它們的含義。
表1 加載區(qū)和執(zhí)行區(qū)信息
表2 重要符號信息
從表1可以看出,整個映像大小為7700(0x00001e14,即Load_region的大小)字節(jié)。映像由不需要移動的Fixed_region和需要重定位的 Relocate_region組成。Relocate_region的大小為0x70字節(jié),堆棧和堆的大小均為0x1000字節(jié)。執(zhí)行區(qū)Fixed_region包含大部分 RO節(jié)、全部RW節(jié)和ZI節(jié)。其中,前兩部分的大小由表2中的Image$$-Fixed_region$$Limit給出,ZI節(jié)的大小則可以根據(jù)表3計算得到,即0x2140-(0x1e14-0x1e00)-0x1000-0x1000=0x12c(去除了堆和堆棧占據(jù)的空間)。
表3 映像信息
另外,也可以從Fixed_region的內(nèi)容得到驗證,RW節(jié)的大小為0x14(0x1da4~0x1d90,即 Section Name為.data的那些數(shù)據(jù)),ZI節(jié)的大小為0x12c(0x1ed0~0x1da4,即Section Name為.bss的那些數(shù)據(jù))。
由于__main函數(shù)是一個庫函數(shù),沒有源代碼,這樣只能通過單步調(diào)試的方式瀏覽它的匯編代碼,或者使用反匯編工具(例如IDA,The Interactive Disassembler)分析映像文件獲得源代碼。
區(qū)表(Region Table)位于地址0x20001D70(符號Region$$Table$$Base,參見 at91sam9261-sdram.map 文件)和0x20001D90(符號 Region$$Table$$Limit)之間。它用于存儲一些重要的數(shù)據(jù),32個字節(jié)一組,分別表示需要處理的數(shù)據(jù)的源地址、目的地址、大小和處理函數(shù)。區(qū)表作為一個核心數(shù)據(jù)結構,數(shù)據(jù)塊的拷貝和清零都在它的控制之下。
本例的區(qū)表如表4所列。它包含兩個條目:第一個條目表示調(diào)用__scatterload_copy函數(shù)從地址0x20001DA4處拷貝0x70個字節(jié)到地址0x300000處,即重定位Relocate_region區(qū),對應圖2中的“①”;第二個條目表示調(diào)用__scatterload_zeroinit函數(shù)將自地址0x20001DA4開始的0x12C個字節(jié)清零,即清零ZI節(jié),對應于圖2中的“②”。
表4 區(qū) 表
__main函數(shù)的處理流程如圖3所示?;舅枷刖褪且来稳〕鰠^(qū)表中的各個條目,以第4個整數(shù)作為處理函數(shù),以前3個整數(shù)作為處理函數(shù)的參數(shù),調(diào)用處理函數(shù)。在處理完區(qū)表中所有條目之后,跳轉到__rt_entry函數(shù);在初始化完堆棧、堆和庫之后,最終將控制權轉交給__main函數(shù)。
圖3 __main函數(shù)流程
__scatterload_rt2 函數(shù)首先分別將 Region$$Table$$-Base和 Region$$Table$$Limit加載到寄存器 R10和 R11中。__scatterload_null函數(shù)取出區(qū)表中的條目并調(diào)用相應的處理函數(shù),即調(diào)用__scatterload_copy拷貝Relocate_region到0x300000,以及調(diào)用__scatterload_zeroinit零初始化始于0x20001DA4大小為0x12C的ZI節(jié)。下面的匯編代碼按照地址、機器碼和指令的次序布局,例如“0x2000005C E08AA000 ADD R10,R10,R0”的含義為地址0x2000005C處有一條機器碼為 E08AA000的指令“ADD R10,R10,R0”。
__main:
0x2000004C EB000000 BL__scatterload_rt2(0x20000054)0x20000050 EB00066E BL__rt_entry(0x20001A10)
__scatterload_rt2:
;構造 R0,加載 Region$$Table$$Base和 Region$$Table$$Limit
;如果R10=R11,則已處理完RegionTable中的所有條目,跳轉;到__rt_entry
完成重定位和零初始化ZI節(jié)之后,R10等于R11,跳轉到__rt_entry函數(shù),為堆棧和堆開辟存儲器空間(如圖2中③所示)、初始化C運行時庫,最后調(diào)用__main函數(shù)。
本文針對RealView工具鏈詳細闡述了映像文件的內(nèi)部結構、加載視圖與執(zhí)行視圖之間的區(qū)別和轉換等底層概念,解釋了進入__main函數(shù)之前系統(tǒng)都發(fā)生了什么。雖然這些工作都不需要程序員編碼實現(xiàn),但是知道它們的存在和它們的默認實現(xiàn),有助于加深對系統(tǒng)的了解和認識。
[1]Sloss Andrew N,Symes Dominic,Wright Chris.ARM嵌入式系統(tǒng)開發(fā)——軟件設計與優(yōu)化[M].沈建華,譯.北京航空航天大學出版社,2005.
[2]Seal David.ARM Architecture Reference M anual[M].2nd Edition.London:Addison-Wesley,2000.
[3]ARM Limited.RealView編譯工具2.0版—開發(fā)者指南.
[4]Bryant Randal E,O'Hallaron David.深入理解計算機系統(tǒng)(修訂版)[M].龔奕利,雷迎春,譯.北京:中國電力出版社,2004.