1. 程式人生 > >ARM彙編初始化C程式執行環境

ARM彙編初始化C程式執行環境

ARM映像檔案簡介

1.ARM映像檔案

      ARM中的各種原始檔(包括彙編檔案,C語言程式及C++程式等)經過ARM編譯器編譯後生成ELF格式的目標檔案。這些目標檔案和相應的C/C++執行時用到的庫經過ARM聯結器處理後,生成ELF格式的映像檔案(image),這種ELF格式的映像檔案是一種可執行檔案,可被寫入嵌入式裝置的ROM中。

      ARM映像檔案的組成:ARM映像檔案是一個層次性結構的檔案,包括了域(region),輸出段(output section)和輸入段(input section)。

一個映像檔案由一個或者多個域組成;每個域最多由三個輸出段組成組成;每個輸出段又包含一個或者輸入段;各輸入端包含了目標檔案中的程式碼和資料。

      所謂域,指的就是整個bin映像檔案所處在的區域,它又分為載入域和執行域。載入域就是映像檔案被靜態存放的工作區域,一般來說flash裡的整個bin檔案所在的地址空間就是載入域當然程式一般都不會放在flash裡執行,一般都會搬到sdram裡執行工作,它們在被搬到sdram裡工作所處的地址空間就是執行域。

我們輸入的程式碼,一般有程式碼部分和資料部分,這就是所謂的輸入段,每個輸入段都有相應的屬性,可以為只讀(ro),可讀寫的(rw)以及初始化成0的(zi)。ARM聯結器根據各輸入段的屬性將這些輸入段分組,再組成對應屬性的輸出段。對於載入域中的輸出段,一般來說ro段後面緊跟著rw段,rw段後面緊跟著zi段。在執行域中這些輸出段並不連續,但rw和zi一定是連著的。zi段和rw段中的資料其實可以是rw屬性。

通常一個映像檔案中包含若干個域,各個域又包含若干的輸出段。ARM聯結器就需要知道如下資訊以決定生成相應的映像檔案。

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

      根據映像檔案中地址對映的複雜程度有兩種方法告訴ARM聯結器這些相關的資訊。

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

      (2)當映像檔案地址對映關係更復雜時,可以使用一個配置檔案(分散載入檔案)告訴聯結器相關的地址對映關係。

2.簡單的初始化使用者程式的執行環境

      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
|Image$$RW$$Base| :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三段拷貝到指定的位置。

      以上介紹摘自博友麥田裡的一條狗。

以下為初始化C程式執行環境的彙編程式碼。

	IMPORT |Image$$RO$$Base| ;載入RO段起始地址
	IMPORT |Image$$RO$$Limit| ;載入RO段結束地址加1
	IMPORT |Image$$RW$$Base| ;載入RW段起始地址
	IMPORT |Image$$RW$$Limit|
	IMPORT |Image$$ZI$$Base|
	IMPORT |Image$$ZI$$Limit|

	IMPORT main;宣告C程式的main()函式

	AREA Start,CODE,READONLY ;宣告程式碼段Start
	ENTRY			 ;標示程式入口
	CODE32			 ;宣告32位ARM指令

Reset   LDR SP,=0x40003F00

	;初始化C程式的執行環境
	LDR R0,=|Image$$RO$$Limit|	;取ROM區中資料段的首地址
	LDR R1,=|Image$$RW$$Base|	;取RAM區中RW段的目標首地址
	LDR R3,=|Image$$ZI$$Base|	;取RAM區中ZI段的首地址

	CMP R0,R1	
	BEQ LOOP1	;相等代表當前是在RAM中執行

LOOP0   CMP R1,R3	
	LDRCC R2,[R0],#4	;如果R1<R3,則把R0地址上的資料讀出到R2中,然後R0=R0+4
	STRCC R2,[R1],#4
	BCC   LOOP0

LOOP1 	LDR R1,=|Image$$ZI$$Limit|
	MOV R2,#0
	
LOOP2 	CMP R3,R1
	STRCC R2,[R3],$4
	BCC
	
	B main
	
	END