"/>
999精品在线视频,手机成人午夜在线视频,久久不卡国产精品无码,中日无码在线观看,成人av手机在线观看,日韩精品亚洲一区中文字幕,亚洲av无码人妻,四虎国产在线观看 ?劉浩
(青島職業技術學院信息學院,青島 266555)
使用μ Vision進行ARM嵌入式軟件開發的工程師,在閱讀μ Vision自動生成的引導代碼之后會發現它并沒有直接調用main函數,而是調用了一個奇怪的__main函數,并且手冊中沒有相關的解釋。雖然表面上看起來這并不是什么大問題,但是實際上這里面蘊含著一些重要的概念,例如映像結構、分散加載機制和重定位等。掌握了這些概念之后,可以更好地理解系統初始化過程。由于__main函數位于ARM C庫中,沒有提供源代碼,為此本文通過反匯編的方法從源代碼級別詳細地闡述了__main函數的功能:復制重定位區、初始化ZI節,以及初始化堆棧和堆等。示例工程getting-started-project-at91sam9261-ek運行在Atmel公司的AT91SAM9261-EK評估板上,集成開發環境為 Keil公司的 μ Vision3.62c,配置使用 Real-View工具鏈。
C語言源文件至少經過預處理、編譯和鏈接3個階段,才能生成最終的可執行映像文件。在預處理階段,預處理器對源文件進行頭文件和宏替換。編譯與鏈接過程如圖1所示。在編譯階段,編譯器分別對各個源文件進行編譯生成對應的對象文件。在鏈接階段,編譯階段生成的對象文件、其他庫和分散加載文件一起作為鏈接器的輸入,生成最終的可執行文件,同時生成的還有鏈接地址映射文件,它包含了關于映像的節、符號表和存儲器映射等信息。

圖1 編譯與鏈接過程
在嵌入式系統中,為了最大限度地提高系統效率,通常需要將一些關鍵代碼(例如異常處理器)和頻繁訪問的數據(例如異常向量)定位到訪問速度較快的存儲器中。RealView工具鏈使用分散加載機制來創建具有復雜存儲器映射的映像。下面的分散加載文件sdram.sct是為了在外部SDRAM中調試程序而編寫的。

分散加載文件用來描述代碼和數據加載時和執行時應在的位置。以sdram.sct為例,它定義了1個加載區和4個執行區。應用程序的映像文件存儲在起始地址為0x20000000的加載區Load_region中。加載視圖和執行視圖如圖2所示。系統上電后,除了異常向量VECTOR需要重定位到起始地址為0x00300000的片內SRAM以外,其余的代碼和數據的地址保持不變。也就是說,符號的加載地址和執行地址并不是完全匹配的,例如VECTOR的加載地址為0x20001da4而執行地址為0x00300000,而且在加載視圖中根本不存在堆、堆棧和ZI節。但是從加載視圖到執行視圖的轉換并不是自動完成的,這部分代碼位于庫函數__main中,它主要負責將VECTOR從Load_region區移動到Relocate_region區,初始化ZI區、堆和堆棧,最后調用main函數。

圖2 加載視圖和執行視圖
鏈接器armlink在生成可執行文件的同時,還會生成一個鏈接地址映射文件at91sam9261-sdram.map。它包含了映像文件的各種信息,例如交叉引用、符號鏈接地址,以及加載區和執行區的基址、大小和內容等。表1和表2列出了一些__main函數中需要使用的重要信息,對照圖2可以更加清楚地理解它們的含義。

表1 加載區和執行區信息

表2 重要符號信息
從表1可以看出,整個映像大小為7700(0x00001e14,即Load_region的大小)字節。映像由不需要移動的Fixed_region和需要重定位的 Relocate_region組成。Relocate_region的大小為0x70字節,堆棧和堆的大小均為0x1000字節。執行區Fixed_region包含大部分 RO節、全部RW節和ZI節。其中,前兩部分的大小由表2中的Image$$-Fixed_region$$Limit給出,ZI節的大小則可以根據表3計算得到,即0x2140-(0x1e14-0x1e00)-0x1000-0x1000=0x12c(去除了堆和堆棧占據的空間)。

表3 映像信息
另外,也可以從Fixed_region的內容得到驗證,RW節的大小為0x14(0x1da4~0x1d90,即 Section Name為.data的那些數據),ZI節的大小為0x12c(0x1ed0~0x1da4,即Section Name為.bss的那些數據)。
由于__main函數是一個庫函數,沒有源代碼,這樣只能通過單步調試的方式瀏覽它的匯編代碼,或者使用反匯編工具(例如IDA,The Interactive Disassembler)分析映像文件獲得源代碼。
區表(Region Table)位于地址0x20001D70(符號Region$$Table$$Base,參見 at91sam9261-sdram.map 文件)和0x20001D90(符號 Region$$Table$$Limit)之間。它用于存儲一些重要的數據,32個字節一組,分別表示需要處理的數據的源地址、目的地址、大小和處理函數。區表作為一個核心數據結構,數據塊的拷貝和清零都在它的控制之下。
本例的區表如表4所列。它包含兩個條目:第一個條目表示調用__scatterload_copy函數從地址0x20001DA4處拷貝0x70個字節到地址0x300000處,即重定位Relocate_region區,對應圖2中的“①”;第二個條目表示調用__scatterload_zeroinit函數將自地址0x20001DA4開始的0x12C個字節清零,即清零ZI節,對應于圖2中的“②”。

表4 區 表
__main函數的處理流程如圖3所示。基本思想就是依次取出區表中的各個條目,以第4個整數作為處理函數,以前3個整數作為處理函數的參數,調用處理函數。在處理完區表中所有條目之后,跳轉到__rt_entry函數;在初始化完堆棧、堆和庫之后,最終將控制權轉交給__main函數。

圖3 __main函數流程
__scatterload_rt2 函數首先分別將 Region$$Table$$-Base和 Region$$Table$$Limit加載到寄存器 R10和 R11中。__scatterload_null函數取出區表中的條目并調用相應的處理函數,即調用__scatterload_copy拷貝Relocate_region到0x300000,以及調用__scatterload_zeroinit零初始化始于0x20001DA4大小為0x12C的ZI節。下面的匯編代碼按照地址、機器碼和指令的次序布局,例如“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節之后,R10等于R11,跳轉到__rt_entry函數,為堆棧和堆開辟存儲器空間(如圖2中③所示)、初始化C運行時庫,最后調用__main函數。
本文針對RealView工具鏈詳細闡述了映像文件的內部結構、加載視圖與執行視圖之間的區別和轉換等底層概念,解釋了進入__main函數之前系統都發生了什么。雖然這些工作都不需要程序員編碼實現,但是知道它們的存在和它們的默認實現,有助于加深對系統的了解和認識。
[1]Sloss Andrew N,Symes Dominic,Wright Chris.ARM嵌入式系統開發——軟件設計與優化[M].沈建華,譯.北京航空航天大學出版社,2005.
[2]Seal David.ARM Architecture Reference M anual[M].2nd Edition.London:Addison-Wesley,2000.
[3]ARM Limited.RealView編譯工具2.0版—開發者指南.
[4]Bryant Randal E,O'Hallaron David.深入理解計算機系統(修訂版)[M].龔奕利,雷迎春,譯.北京:中國電力出版社,2004.