新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > ARM基礎(chǔ)知識 -- ELF映像文件

ARM基礎(chǔ)知識 -- ELF映像文件

作者: 時間:2016-11-28 來源:網(wǎng)絡(luò) 收藏
記錄一些簡單的ARM的映像文件的內(nèi)容組成及原理。

1.ARM映像文件(axf和bin文件)的組成。

本文引用地址:http://m.butianyuan.cn/article/201611/322691.htm

ARM是32位處理器,地址位寬也是32位,因此其存儲器的映射范圍可以達(dá)到4GB空間?;旧蠈τ贏RM處理器,上電或復(fù)位時都會從0x00000000出開始執(zhí)行指令,因此必須保證映像文件的起始位置放置在0x00000000處,無論是采用NAND或NOR flash,這一點都無法改變。正確放置之后,處理器會獲取到正確的指令從而順序執(zhí)行。

ARM的映像文件(即可執(zhí)行文件)。生成的ARM映像文件有分為axf和bin兩種。bin文件時真正的可執(zhí)行文件,而axf文件是ARM特有的調(diào)試文件,除了包含了bin文件的內(nèi)容外還包含了很多其他的調(diào)試信息。在axf的文件頭和文件尾部都包含了可以用在ADW或AXF的load image的調(diào)試中。

2.ARM的映像文件的加載域和運行域的不同

加載域映像文件。盡量簡單地說,即那些可執(zhí)行文件例如bin文件,一般由域組成。而域由最多的三個輸出段組成即(RO、RW、ZI),RO是只讀的代碼段,RW是可讀寫的數(shù)據(jù)段和ZI未初始化的數(shù)據(jù)段。分析bin映像文件的具體內(nèi)容,也可以印證上面的內(nèi)容,基本上在bin的前半部分是RO的內(nèi)容而后半部分是RW的內(nèi)容,ZI由于是為初始化數(shù)據(jù),因此不需要保存在bin文件中。即bin文件時RO+RW的內(nèi)容的集合。而這三個輸出段又是可以由多個輸入段組成的,因為在匯編文件中,可以設(shè)置多個段名稱,只需要在鏈接的時候鏈接到相應(yīng)的位置即可,因此多個輸入段可以對應(yīng)到一個輸出段上。上面所說的bin文件都是指的是加載域的情況,因為這都是可執(zhí)行文件被初始放置在flash中時各個部分的分布情況,即是加載到系統(tǒng)時的情況,所以叫加載域。但系統(tǒng)此時是并不能運行的。

加載域的映像文件必須順利地過渡到運行時域,這時系統(tǒng)才能夠正確地被執(zhí)行。因為有個很明顯的一點,程序一般都固化在flash中。而flash是只讀的,上面也說到可讀寫的RW數(shù)據(jù)段的內(nèi)容是跟在RO段后面(即bin文件中),被放置在了flash上,RW段要求可讀寫,flash顯然不滿足要求,因此加載域必須過渡到運行時域。最直觀的理解就是,我們必須把RW段的內(nèi)容轉(zhuǎn)移到可讀寫的SDRAM或SRAM上去,因此就引發(fā)了運行域的問題。

如何轉(zhuǎn)換,如何保證前面RO段的程序的內(nèi)容能夠正確地尋址到被轉(zhuǎn)移了的RW段的內(nèi)容。因為大部分匯編程序的轉(zhuǎn)移指令都是絕對尋址的,比較少的偽指令能提供相對尋址,絕對尋址的效率顯然比較高。因此我們必須在代碼中就必須知道將來運行時RW段被放置在了什么一個地方。在程序鏈接之后,所有的代碼中的地址都將固定。解決這樣的問題也并不復(fù)雜,需要鏈接器確保RO段的運行時起始地址和RW段的運行時起始地址,這就是為什么我們要在ADS設(shè)置連接選項ro_base和rw_base的目的了。所有的RO段的地址都是基于ro_base指定的內(nèi)容,而所有代碼段的內(nèi)容也是基于rw_base上的,這樣程序在鏈接后就已經(jīng)確定了所有的相對地址,剩下的事就是將相應(yīng)的段的內(nèi)容從加載域的位置搬移到運行時域的位置。

這樣的代碼搬移的工作如果是在調(diào)試狀態(tài)的話,一般調(diào)試器就會幫我們做好所有事情了,而如果是在非調(diào)試狀態(tài),就需要我們自己復(fù)制代碼段的搬移工作,有趣的是,不少ARM都支持從NAND flash中啟動,而NAND flash本身就是不能直接執(zhí)行的,需要將代碼搬移到SDRAM中,因此這里的運行時域和加載域的區(qū)別被屏蔽掉了。一般我們做代碼搬移這樣的工作的時候,采用的跳轉(zhuǎn)地址都要用相對跳轉(zhuǎn)指令。這樣的好處是,無論用戶將程序加載到什么地址,代碼搬移指令都能正確地將程序從加載域轉(zhuǎn)換到運行時域,從而保證程序順利執(zhí)行。

1.ELF格式文件的結(jié)構(gòu)

1.1 映像文件組成部分

* 一個映像文件有一個或多個域組成
* 每個域包含一個或多個輸出段
* 每個輸出段包含一個或多個輸入段
* 各輸入段中包含了目標(biāo)文件中的代碼和數(shù)據(jù)

輸入段中包含了四類內(nèi)容:代碼、已經(jīng)初始化的數(shù)據(jù)、未經(jīng)初始化的存儲區(qū)域、內(nèi)容初始化成0的存儲區(qū)域。每個輸入段有相應(yīng)的屬性,可以為只讀的(RO)、可讀寫的(RW)以及初始化成0的(ZI)。ARM連接器根據(jù)個輸入段的屬性將這些輸入段分組,再組成不同的輸出段及域。

一個輸出段中包含了一系列的具有相同的RO、RW和ZI屬性的輸入段。輸出段的屬性與其中包含的輸入段的屬性相同。在一個輸出段的內(nèi)部,各輸入段是按照一定的規(guī)則排序的,這將在1.3節(jié)油詳細(xì)地介紹。

一個域中包含1-3個輸出段,其中個輸出段的屬性各不相同。各輸出段的排列順序是由其屬性決定的。其中RO屬性的輸出段排在最前面,其次是RW屬性的輸出段,最后是ZI屬性的輸出段。一個域通常映射到一個物理存儲器上,如ROM或RAM。

1.2 ARM映像文件各組成部分的地址影射

ARM映像文件各組成部分在存儲系統(tǒng)中的地址有兩種:一種是映像文件位于存儲器中時(也就是該映像文件運行之前)的地址,稱之為加載地址;一種是映像文件運行時的地址,稱之為運行時地址。之所以有這兩種地址,是因為映像文件在運行時,其中的有些域是可以移動的新的存儲區(qū)域。比如,已經(jīng)初始化的RW屬性的數(shù)據(jù)所在的段運行之前可能保存系統(tǒng)的ROM中,在運行時,他被移動至RAM中。

通常,一個映像文件包含若干個域,各域又包含若干的輸出段。ARM連接器需要知道如下的信息,已決定如何生成相應(yīng)的映像文件。

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

根據(jù)映像文件中地址映射的復(fù)雜程度,有兩種方法來告訴arm連接器這些相關(guān)信息。對于映像文件中地址映射關(guān)系比較簡單的情況,可以使用命令行選項;對于映像文件中地址映射關(guān)系比較復(fù)雜的情況,可以使用一個配置文件。

2.arm映像文件的入口點

2.1 arm映像文件的入口點有兩種類型:一種是映像文件運行時的入口點,稱為初始入口點(initial entry point),另一種是普通入口點(entry point).

初始入口點是映像文件運行時的入口點,每個映像文件只有一個唯一的初始入口點,它保存在ELF頭文件中。如果映像文件是被操作系統(tǒng)加載的,操作系統(tǒng)是通過跳轉(zhuǎn)到該初始入口點處來加載該映像文件。

普通的入口點是在匯編中用ENTRY偽操作定義。他通常用于標(biāo)志該段代碼是通過異常中斷處理程序進(jìn)入的。這樣連接器刪除無用的段時不會將該段代碼刪除。一個映像文件中可以定義多個普通入口點。

應(yīng)該注意的是,初始入口點可以使普通入口點,但也可以不是普通入口點。

2.2定義初始入口點

初始入口點必須滿足下面兩個條件:

* 初始入口點必須位于映像文件的運行時域內(nèi)。
* 飽含初始入口點的運行時域不能被覆蓋,他的加載地址和運行地址必須是相同的。

可以使用連接選項-entry address來指定映像文件的初始入口點。這時,address指定了映像文件的初始入口點的地址值。

對于地址0x0處為rom的嵌入式應(yīng)用系統(tǒng),可以使用-entry 0x0來指定映像文件的初始入口點。這樣當(dāng)系統(tǒng)復(fù)位后,自動跳轉(zhuǎn)到該入口開始執(zhí)行。

如果映像文件是被一個加載器加載的,該映像文件該映像文件必須包含一個初始化入口點。這種映像文件通常還包含了其他普通入口點,這些普通入口點一般為異常中斷處理程序的入口地址。

當(dāng)用戶沒有指定-entry address時,連接器根據(jù)下面的規(guī)則決定映像文件的初始入口點。

* 如果輸入的目標(biāo)文件中只有一個普通入口點,該普通入口點被連接器當(dāng)成映像文件的初始入口點。

* 如果輸入的目標(biāo)文件中沒有一個普通入口點,或者其中的普通入口點多于一個,則連接器生成的映像文件中不包含初始入口點,并產(chǎn)生警告信息。

2.3普通入口點的用法

普通入口點是在匯編中用ENTRY 偽操作定義。在嵌入式應(yīng)用中,各異常中斷的處理程序入口使用普通入口點標(biāo)示。這樣連接器在刪除無用段時不會將該段代碼刪除。

一個映像文件中可以定義多個普通入口點。沒有指定連接選項-entry addres時,如果輸入的目標(biāo)文件中只有一個普通入口點,該入口點被連接器當(dāng)成映像文件的初始入口點。

3 輸入段的排序規(guī)則

連接器根據(jù)輸入段的屬性來組織這些輸入段,具有相同屬性的輸入段被放到域中一段連續(xù)的空間中,組成一個輸出段。在一個輸出段中,各輸入段的起始地址與輸出段的起始地址和該輸出段中個輸入段的排列順序有關(guān)。

通常情況下,一個輸出段中個輸入段的排列順序由下面幾個因素決定的。用戶可以通過連接選項-first和-last來改變這些規(guī)則。

* 輸入段的屬性。
* 輸入段的名稱
* 各輸入段在連接命令行的輸入段列表中的排列順序

按照輸入段的屬性,其排列順序如下所示:

* 只讀的代碼段
* 只讀的數(shù)據(jù)段
* 可讀寫的代碼段
* 其他已經(jīng)初始化的數(shù)據(jù)段
* 未出世化的數(shù)據(jù)

對于具有相同屬性的輸入段,按照其名稱來排序。這是輸入段名稱是區(qū)分大小寫的,按照其ASCII碼順序進(jìn)行排序。

對于具有相同屬性和名城的輸入段,按照其在輸入段列表中的順序進(jìn)行排序。也就是說,幾十個輸入段的屬性和名稱保持不變,如果其在編譯時,各輸入段在輸入段列表中的排列順序不同,生成的映像文件也將不同。

可以通過連接選項-first和-last來改變這些規(guī)則。如果連接時使用了配置文件,可以在配置文件中通過偽屬性FIRST和LAST達(dá)到相同的效果。

連接選項-first和-last不能改變根據(jù)輸入段進(jìn)行排序的規(guī)則,它只能改變根據(jù)輸入段名稱和其在輸入列表中的順序的排序規(guī)則。也就是說,如果使用-first指定

一個輸入段,只有該輸入段所在的輸出段位于運行時域的開始位置時,該輸入段才能位于整個運行時域的開始位置。

各個輸入段排好順序后,在確定各個輸入段的起始地址之前,何以通過填充補丁是個輸入段滿足地址對齊的要求。

ARM連接器介紹

ARM連接器armlink將編譯得到的ELF格式文件以及相關(guān)的C/C++運行時庫連接生成相應(yīng)的結(jié)果文件。armlink可以完成下面的操作:

* 連接編譯后得到的目標(biāo)文件相應(yīng)的c/c++運行時庫,生成可執(zhí)行的影像文件。
* 將一些目標(biāo)文件進(jìn)行連接,生成一個新的目標(biāo)文件,供將來進(jìn)一步連接時使用,這成為部分連接。
* 指定代碼和數(shù)據(jù)在內(nèi)存中的位置。
* 生成被連接文件的調(diào)試信息和相互間的引用信息。

Armlink在進(jìn)行部分連接和完全生成可執(zhí)行文件時作進(jìn)行的操作是不同的。下面分別介紹:

(1)解析輸入的目標(biāo)文件之間的符號引用關(guān)系。
(2)根據(jù)輸入目標(biāo)文件對c/c++函數(shù)的調(diào)用關(guān)系,從c/c++運行時庫中提取相應(yīng)模塊。
(3)將各個輸入段排序,組成相應(yīng)的輸出段。
(4)刪除重復(fù)的調(diào)試信息。
(5)根據(jù)用戶指定的分組和定位信息,建立映像文件的地址映射關(guān)系。
(6)重定位需要重定位的值。
(7)生成可執(zhí)行的映像文件。

armlink在進(jìn)行部分連接生成新的目標(biāo)文件時執(zhí)行下面的操作。

(1)刪除重復(fù)的調(diào)試信息
(2)最小化符號表的大小
(3)保留那些未被解析的符號
(4)生成新的目標(biāo)文件

下面根據(jù)各armlink的命令行選項的功能分類列舉了armlink的命令行選項,各選項的具體用法將在后面有詳細(xì)地介紹。

* 提供關(guān)于armlink的幫助信息
* 指定輸出文件的名稱和類型:*-output;*-partial;*-elf
* 使用選項文件,其中可以包含一些連接選項。
* 制定可執(zhí)行映像文件的內(nèi)存映射關(guān)系。*-rwpi;*-ropi;*-rw_base;*-ro_base;*-spit;*-scatter
* 控制可執(zhí)行映射文件的內(nèi)容。*-first;*-last
* 生成與映像文件的相關(guān)信息
* 控制armlink生成相關(guān)的診斷信息。




評論


技術(shù)專區(qū)

關(guān)閉