ARM映像文件

ARM映像文件

ARM中的各種源文件(包括彙編文件,C語言程序及C++程序等)經過ARM編譯器編譯後生成ELF(Executable and linking format)格式的目標文件。這些目標文件和相應的C/C++運行時用到的庫經過ARM連接器處理後,生成ELF格式的映像文件(image),這種ELF格式的映像文件是一種可執行文件,可被寫入嵌入式設備的ROM 中。

bin文件是真正的可執行文件,axf文件是ARM的調試文件,除了包含bin的內容之外,還附加了其他的調試信息,這些調試信息加在可執行的二進制數據的前面,所以把axf文件寫到ARM的指令執行地址(一般是0x0)將不能運行,因爲在此地址前幾十個字節的數據不是可執行的二進制數據,而是頭部的調試信息;而bin文件正是去掉了調試信息的可以執行的“精華”部分。

ARM映像文件的組成

ARM映像文件是一個層次性結構的文件,包括了域(region),輸出段(output section)和輸入段(input section)。一個映像文件由一個或者多個域組成;每個域最多由三個輸出段組成組成;每個輸出段又包含一個或者多個輸入段;各輸入端包含了目標文件中的代碼和數據。

相關術語:

1.域 (region):一個映象文件由一個或多個域組成。反過來說域是組成映象文件的最大的結構。所謂域,指的就是整個bin映像文件所處在的區域,它又分爲加載域和運行域。加載域就是映像文件被靜態存放的工作區域,一般來說flash裏的整個bin文件所在的地址空間就是加載域,當然程序一般都不會放在flash裏執行,一般都會搬到sdram裏運行工作,它們在被搬到sdram裏工作所處的地址空間就是運行域。一個域通常映射到一個物理存儲器上,如ROM和RAM等。

2.段(Section):一個域包含一個或多個輸出段,一個輸出段包含一個或多個輸入段。我們輸入的代碼,一般有代碼部分和數據部分,這就是所謂的輸入段,每個輸入段都有相應的屬性,可以爲只讀(ro),可讀寫的(rw)以及初始化成0的(zi)。

3.RO,RW,ZI:輸入段中包含4類內容:代碼、已經初始化的數據、未經初始化的存儲區域、內容初始化爲0的存儲區域。每個輸入段有相應的屬性,可以爲只讀(RO)、可讀寫(RW)以及初始化爲0的(ZI)。ARM連接器根據各輸入段的屬性將這些輸入段分組,再組成對應屬性的輸出段。對於加載域中的輸出段,一般來說ro段後面緊跟着rw段,rw段後面緊跟着zi段。在運行域中這些輸出段並不連續,但rw和zi一定是連着的。zi段和rw段中的數據其實可以是rw屬性。

 注:

(1)C中的指令以及常量被編譯後是RO類型數據。

(2)C中的未被初始化或初始化爲0的變量編譯後是ZI類型數據。

(3)C中的已被初始化成非0值的變量編譯後市RW類型數據。

4.加載時地址:是映象文件位於存儲器(還沒有運行,一般在ROM中)時的地址

5.運行時地址:是映象文件運行時的地址。

通常一個映像文件中包含若干個域,各個域又包含若干的輸出段。ARM連接器就需要知道如下信息以決定生成相應的映像文件。燒錄到ROM中的image文件與實際運行時的ARM程序之間並不是完全一樣的。因此就有必要了解ARM程序是如何從ROM中的image到達實際運行狀態的。

    *分組信息 :決定如何各將輸入段組織成相應的輸出段和域。
    *定位信息 :決定各個域在存儲器空間中的起始地址。

根據映像文件中地址映射的複雜程度有兩種方法告訴ARM連接器這些相關的信息。

(1)當映像文件中最多包含兩個域,每個域最多有三個輸出段時,可以使用連接器選項告訴連接器相關的地址映射關係。選項有-ropi,-rwpi,-ro_base,-rw_base,-split等。

(2)當映像文件地址映射關係更復雜時,可以使用一個配置文件(分散加載文件)告訴連接器相關的地址映射關係。

ARM映像文件數據移動:

上面已經提到了RW段加載地址一般在ROM中,運行時需要被搬運到RAM中。加載時狀態的映象文件中的RO、RW和ZI的地址都是臨時的,他們在運行時要被BootLoader程序搬運到真正的運行時地址。這個地址是連接時設置的地址。這個問題很重要,如果在編譯前沒有正確的設置運行時地址,那麼程序就不能被搬運到正確的RAM地址中運行。

=======================================================================================================

 瞭解了以上內容,那麼就可以打開ADS1.2來看一下具體的設置。

打開ADS的一個工程後,點擊如下圖所示的Debug Settings按鈕打開對話框。打開Target Settings對話框後,在左邊列表中選擇Linker選項。點擊它下面的的ARM Linker。然後在右面的選項卡選擇Output選項卡。如下圖所示。

 

ARM映像文件 - tianwaike1 - 開拓-進取

 

看看ADS 開發文檔ARM Developer suite 1.2 的ADS_CodeWarriorIDEGuide.pdf 怎麼說的

RO Base  This text field sets both the load address and execution address of the region containing the RO

                 section. If you do not enter a value, the value defaults to 0x8000.

意思是,這個文本框設置加載時地址和運行時地址。如果沒有設置值,默認時0x8000。這個值將會對應ADS的預定義變量Image$$RO$$Base,指定了RO的base。這個變量可以被初始化程序IMPORT進去。這個參數有兩個意思:

1.如果生成可執行bin文件燒寫到flash中去,那麼這個地址就是要燒到flash中的地址(一般是0x0)。這裏又出現一個問題,如果使用的ARM芯片是支持memory remap的(如三星的4510芯片),那麼可以在bootloader程序中將RO段搬運到RAM中,再把RAM remap 到0x0,這樣系統讀取RO段的時候就可以在RAM中讀了。如果ARM芯片不支持remap(如三星的44b0x),那麼RO段不能搬運到RAM中,而在FLASH中讀取。

2.如果生成afx調試文件,那麼這個地址是調試時加載到RAM中的地址。

根據上面的1,2可知,如果要燒寫FLASH 那麼RO Base 應該設置成ARM片選的FLASH 的首地址;如果要調試那麼RO Base要設置成RAM地址。

RW Base   這個文本框設定包含RW和ZI輸出段的運行時域地址。如果你在這裏輸入一個值,連接器創建一個包含兩個運行時域的映象,這兩個域是:

包含RO輸出段的運行時域

包含RW和ZI輸出段的運行時域

如果你輸入了RW Base值並且選擇了Split image選項,連接器創建的映象文件分別包含RW輸出段和ZI輸出段的裝載時地址和運行時地址,並都由你輸入的RW Base值指定。

對於簡單連接方式,當沒有輸入RW Base值時,映象文件包含一個加載時域和一個運行時域。這時,RO輸出段、RW輸出段、ZI輸出段都包含在一個域中。當輸入RW Base值時,映象文件包含兩個運行時域,一個包含RO輸出段,一個包含RW輸出段和ZI輸出段。當指定了-split選項時,映象文件又多包含兩個加載時域,一個包含RO輸出段,一個包含RW輸出段和ZI輸出段。

簡單的初始化用戶程序的執行環境

      ARM映像文件一開始總是存儲在ROM/Flash裏面的,其RO部分既可以在ROM/Flash裏面執行,也可以轉移到速度更快的RAM中執行;而RW和ZI這兩部分是必須轉移到可寫的RAM裏去,其實RW包括ZI區域,ZI區域放的是未賦值的全局變量,RW 區域放的是已賦值(賦0除外)的全局變量。所謂應用程序執行環境的初始化,就是完成必要的從ROM到RAM的數據傳輸和內容清零。

      先介紹幾個必要的符號,編譯器使用下列符號來記錄各段的起始和結束地址:
    |Image$$RO$$Base| :RO段起始地址 
      |Image$$RO$$Limit| :RO段結束地址加1 (在加載域中,是RW的起始地址)
     |Image$$RW$$Base| :RW段起始地址 (在運行域中即運行的時候,是RW的起始地址)
      |Image$$RW$$Limit| :ZI段結束地址加1
     |Image$$ZI$$Base| :ZI段起始地址
      |Image$$ZI$$Limit| :ZI段結束地址加1
     這些符號的值是根據鏈接器中設置的中ro-base和rw-base的設置來計算的。 由於rw和zi相連,|Image$$ZI$$Base|就等於|Image$$RW$$Limit| .其它的值都是編譯器自動計算出來的。我們還可以通過scatter文件更詳細得指定各個輸出段的工作地址。
      初始化用戶執行環境主要是把ro、rw、zi三段拷貝到指定的位置。

下面的程序是rw、zi段在運行域中的搬運過程:

 ;Copy and paste RW data/zero initialized data
    ldr r0, =|Image$$RO$$Limit|     /*取RO區末地址後面的地址,即RW數據源的起始地址*/
    ldr r1, =|Image$$RW$$Base|    /*取RW區在RAM裏的執行區起始地址,即編譯器選項RW_Base指定的地址*/
    ldr r3, =|Image$$ZI$$Base|       /*取ZI區在RAM裏面的起始地址*/
    
    ;Zero init base => top of initialised data
    cmp r0, r1      /* 比較ROM區中數據段首地址和RAM區中RW段目標首地址*/
    beq %F2       /*相等代表當前已經是在RAM中運行*/(F表示after,B表示before,r0與r1相等則轉跳)
                             /*B %F2表向前跳到標號爲2的Lable處*/
1      
    cmp r1, r3               /*不相等則和RAM區中ZI段的目標地址比較*/ 
    ldrcc   r2, [r0], #4     /*如果r1<r3,則把r0地址上的數據讀出到r2中,然後r0=r0+4*/     
    strcc   r2, [r1], #4     /*如果r1<r3,則把r1地址上的數據讀出到r2中,然後r0=r0+4*/
    bcc %B1              /*如果r1<r3,則跳轉到Lable爲1處繼續執行*/
2      
    ldr r1, =|Image$$ZI$$Limit|          /* 取ZI段的結束地址 */
    mov r2, #0                                /*將r2賦值爲0*/
3      
    cmp     r3, r1      ; Zero init
    strcc   r2, [r3], #4    /*如果r3<r1,將r2內容寫入到r3地址單元中,然後r3=r3+4*/     
    bcc     %B3            /*如果r3<r1,則跳轉到Lable爲3處繼續執行*/

 

發佈了20 篇原創文章 · 獲贊 7 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章