<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>

新聞中心

EEPW首頁(yè) > 嵌入式系統 > 設計應用 > ARM開(kāi)發(fā)各種燒寫(xiě)文件格式說(shuō)明(ELF、HEX、BIN)

ARM開(kāi)發(fā)各種燒寫(xiě)文件格式說(shuō)明(ELF、HEX、BIN)

作者: 時(shí)間:2016-11-11 來(lái)源:網(wǎng)絡(luò ) 收藏
一、ELF


Executable and linking format(ELF)文件是x86Linux系統下的一種常用目標文件(object file)格式,有三種主要類(lèi)型:
(1)適于連接的可重定位文件(relocatable file),可與其它目標文件一起創(chuàng )建可執行文件和共享目標文件。
(2)適于執行的可執行文件(executable file),用于提供程序的進(jìn)程映像,加載的內存執行。
(3)共享目標文件(shared object file),連接器可將它與其它可重定位文件和共享目標文件連接成其它的目標文件,動(dòng)態(tài)連接器又可將它與可執行文件和其它共享目標文件結合起來(lái)創(chuàng )建一個(gè)進(jìn)程映像。
ELF文件格式比較復雜。

二、HEX

Intel HEX文件是記錄文本行的ASCII文本文件,在Intel HEX文件中,每一行是一個(gè)HEX記錄,由十六進(jìn)制數組成的機器碼或者數據常量,Intel HEX文件經(jīng)常被用于將程序或數據傳輸
存儲到ROM、EPROM,大多數編程器和模擬器使用Intel HEX文件。
記錄格式
一個(gè)Intel HEX文件可以包含任意多的十六進(jìn)制記錄,每條記錄有五個(gè)域,下面是一個(gè)記錄的格式。
: llaaaatt[dd。。。]cc
每一組字母是獨立的一域,每一個(gè)字母是一個(gè)十六進(jìn)制數字,每一域至少由兩個(gè)十六進(jìn)制數字組成,下面是字節的描述。
: 冒號 是每一條Intel HEX記錄的開(kāi)始
ll 是這條記錄的長(cháng)度域,他表示數據(dd)的字節數目。
aaaa 是地址域,他表示數據的起始地址
tt 這個(gè)域表示這條HEX記錄的類(lèi)型,他有可能是下面這幾種類(lèi)型
00 —-數據記錄
01 —-文件結束記錄
02 —-擴展段地址記錄
04 —-擴展線(xiàn)性地址記錄
dd 是數據域,表示一個(gè)字節的數據,一個(gè)記錄可能有多個(gè)數據字節,字節數目可以
查看ll域的說(shuō)明
cc 是效驗和域,表示記錄的效驗和,計算方法是將本條記錄冒號開(kāi)始的所有字母對
所表示的十六進(jìn)制數字
都加起來(lái)然后模除256得到的余數最后求出余數的補碼即是本效驗字節cc。
: 0300000002005E9D
cc=0×01+NOT((0×03+0×00+0×00+0×00+0×02+0×00+0×5E)%0×100)=0×01+0×9C=0×9D >
數據記錄
Intel HEX文件由若干個(gè)數據記錄組成,一個(gè)數據記錄以一個(gè)回車(chē)和一個(gè)換行結束
比如下面的一條數據記錄
: 10246200464C5549442050524F46494C4500464C33
10 是此行記錄數據的字節數目
2462 是數據在內存中的起始地址
00 是記錄類(lèi)型00(是一個(gè)數據記錄)
464C 到 464C 是數據
33 是此行記錄的效驗和

三、BIN

BIN文件就是直接的二進(jìn)制文件,內部沒(méi)有地址標記。一般用編程器燒寫(xiě)時(shí)從00開(kāi)始,而如果下載運行,則下載到編譯時(shí)的地址即可。

總結:可以由ELF文件轉化為其它兩種文件,HEX也可以直接轉換為BIN文件,但是BIN要轉化為HEX文件必須要給定一個(gè)基地址。而HEX和BIN不能轉化為elf文件,因為ELF的信息量要大。另外還有一種ads的調試文件axf,
它可以轉化為BIN文件,用以下命令 fromelf -nodebug xx。axf -bin xx。bin即可。

本文引用地址:http://dyxdggzs.com/article/201611/316997.htm



這里所說(shuō)的ARM系統基本文件格式,都是在基于A(yíng)RM的嵌入式系統開(kāi)發(fā)中常會(huì )碰到的文件格式。
ARM系統基本文件格式有三種:
1)BIN,平板式二進(jìn)制格式,一般用于直接燒寫(xiě)到Flash中,也可以用于加載到monitor程序中。
2)ELF,EXECUTABLEANDLINKABLEFORMAT,一種通用的OBJECT文件格式,一般由GNUCOMPILERCOLLECTION(GCC)產(chǎn)生。
3)AXF,BIN格式的擴展版,主體部分同BIN,在文件頭和尾加入了調試用的信息,用于A(yíng)XD。
本文主要討論BIN與ELF。
首先說(shuō)明,ELF格式是一種OBJECT文件格式。一般OBJECT文件都可以分成三類(lèi):可重定位OBJECT文件,可執行OBJECT文件,共享OBJECT文件。ELF格式文件也可以分成這三種。
首先說(shuō)說(shuō)可重定位OBJECT文件。這種OBJECT文件一般由GCC中的ASSEMBLER(as)產(chǎn)生(請不要認為GCC只是編譯器),里面除了二進(jìn)制的機器代碼,還有一些可用于進(jìn)行重定位的信息。它主要是作為L(cháng)INKER(ld)的輸入,LINKER將跟據這些信息,將需要重定位的符號重定位,進(jìn)而產(chǎn)生可執行的OBJECT文件。ELF格式的可重定位OBJECT文件由header與section組成。
Header包括ELFheader與sectionheader.ELFheader位于文件的頭部,用于存儲目標機器的架構,大小端配置,ELFheader大小,object文件類(lèi)型,sectionheader在文件中的偏移,sectionheader的大小,sectionheader中的項目數等信息。Sectionheader則定義了文件中每個(gè)section的類(lèi)型,位置,大小等信息。Linker就是通過(guò)查找ELFheader,找到sectionheader的入口,再在sectionheader中找到相應的section入口,進(jìn)而定位到目標section的。
Section包括
.text:經(jīng)過(guò)編譯的機器代碼。
.rodata:只讀的數據,例如printf(“hello!”)中的字符串hello。
.data:已初始化的全局變量,局部變量將在運行時(shí)被存放在堆棧中,不會(huì )在.data或.bss段中出現。
.bss:未初始化的全局變量,在這里只是一個(gè)占位符,在object文件中并沒(méi)有實(shí)際的存儲空間。
.symtab:符號表,用于存放程序中被定義的或被引用到的全局變量和函數的信息。
.rel.text:一個(gè)保存著(zhù)一系列在.text中的位置的列表。這些位置將在linker把這個(gè)文件與其它object文件合并時(shí)被修改,一般來(lái)說(shuō),這些位置都是保存著(zhù)一些引用到全局變量或者外部函數的指令。引用局部變量或者本地函數的指令是不需要被修改的,因為局部變量和本地函數的地址一般都是使用PC相對偏移地址的。需要注意的是,這個(gè)section和下面的.rel.data在運行時(shí)并不需要,生成可執行的ELFobject文件時(shí)會(huì )去掉這個(gè)section。
.rel.data:保存全局變量的重定位信息。一般來(lái)說(shuō),如果一個(gè)全局變量它的初始化值是另一個(gè)全局變量的地址,或者是外部函數的地址,那么它就需要被重定位。
.debug:保存debug信息。
.strtab:一個(gè)字符串表,保存著(zhù).symtab和.debug,和各個(gè)section的名字。.symtab,.debug和sectiontable里面,凡是保存name的域,其實(shí)都是保存了一個(gè)偏移值,通過(guò)這個(gè)偏移值在這個(gè)字符串表里面可以找到相應得字符串。
下面仔細討論一下.symtab:
每一個(gè)可重定位的object文件,都會(huì )有一個(gè).symtab。這個(gè)符號表保存了在這個(gè)object文件中所有被定義的和被引用的符號。當源程序是C語(yǔ)言程序時(shí),.symtab中的符號直接來(lái)源于C編譯器(cc1)。這里所說(shuō)的符號主要有三種:
1)在這個(gè)object文件中被定義的可以被其他object文件全局符號。在C語(yǔ)言源程序中,主要就是那些非靜態(tài)(沒(méi)有static修飾的)的全局變量和非靜態(tài)的函數。在A(yíng)RM匯編語(yǔ)言中,就是那些被EXPORT指令導出的變量。
2)在這個(gè)object文件中引用到,但是在其他文件中定義的全局變量。在A(yíng)RM匯編語(yǔ)言中就是通過(guò)IMPORT命令引入的變量
3)本地變量。本地變量只在本object文件內可見(jiàn)。這里的本地變量指的是連接器本地變量,應該和一般的程序本地變量作區別。這里所指的本地變量,包括用static修飾的全局變量,object文件中section名稱(chēng),源代碼文件名稱(chēng)。一般意義上的本地變量,是在運行時(shí)由系統的運行時(shí)環(huán)境管理的,linker并不關(guān)心。
每個(gè)符合上面條件的符號在.symtab文件中都會(huì )有一個(gè)數據項。這個(gè)數據項的數據結構是:

Typedefstruct{
intname;//符號名稱(chēng),其實(shí)就是.strtab的偏移值
intvalue;//在section中的位置,以相對section地址的偏移表示
intsize;//大小
chartype;//類(lèi)型,一般是數據或函數
charbinding;//是本地變量還是全局變量
charreserved;//保留的位
charsection;//符號所屬的section??蛇x有:.text(用數字1代表),.data(用數
//3代表),ABS(不應被重定位的符號),UND(在本object文件
//中未定義的符號,可能在別的文件中定義),COM(一般的未初//始化的變量符號)。
}ELF_sym

現在假設組成應用的各個(gè)模塊都已經(jīng)被匯編,構建出了可重定位的object文件。這些object的結構都是一樣的,有各自的.text,.datasection,有各自的.symtab.GCC下一步要做的就是使用linker(ld),把這些object文件,加上必要的庫連接成具有絕對運行時(shí)地址的可執行文件,就是可執行的ELF格式的文件。
Linker的連接動(dòng)作可以分為兩部分:
1)符號解析。確定引用符號的指向。
2)符號重定位。合并section,分配運行時(shí)環(huán)境地址,引用符號重定位。
符號解析:
在一個(gè)object文件中,有指令定義了符號,也有指令引用了符號??赡艽嬖谶@樣一種情況,一個(gè)被引用到的符號,有多重的定義。符號解析的作用就是確定,在這個(gè)object文件中,一個(gè)符號引用真正引用的是哪個(gè)符號。
在編譯的時(shí)候,除了在本文件中定義的全局變量會(huì )由編譯器生成一個(gè)符號表項之外,當發(fā)現一個(gè)被引用到的符號在本文件中并沒(méi)有被定義,編譯器也會(huì )自動(dòng)產(chǎn)生一個(gè)符號表項,把確定這些引用的工作留給linker。匯編器在匯編時(shí)將讀取這些符號表項,生成.symtab。在讀取的過(guò)程中,如果發(fā)現有在無(wú)法確定的符號引用項,匯編器會(huì )為這些符號額外生成一個(gè)數據項,稱(chēng)作重定位數據項,存放于rel.text或rel.datasection中,交由linker確定。下面是重定位數據項(relocationentry)的數據結構:

Typedefstruct{
intoffset;//指明需要被重定位的引用在object中的偏移,實(shí)際上就是需要被重定位的引用
//在object中的實(shí)際位置
intsymbol;//這個(gè)被重定位的引用真實(shí)指向的符號
inttype;//重定位類(lèi)型:R_ARM_PC24:使用24bit的PC相對地址重定位引用
//R_ARM_ABS32:使用32bit絕對地址重定位引用
}Elf32_Rel

Linker需要解析的,就是那些被生成了重定位數據項的引用。Linker將根據C語(yǔ)言定義的規則,對于每一個(gè)重定位數據項,在輸入的各個(gè)object文件中查找適合的符號,把這個(gè)符號填入symbol項中。但是由于還不知道這個(gè)符號的真實(shí)地址,所以現在就算知道了引用的真實(shí)指向,但我們還是不能確定這個(gè)引用指向的地址。
符號重定位:
符號重定位用來(lái)解決上面的問(wèn)題。Linker首先進(jìn)行section的合并。Linker合并object文件的過(guò)程很簡(jiǎn)單,一般就是相同屬性的section合并,例如不同object文件的.textsection將被合并成一個(gè).text。同樣,.symtabsection也被合并成一個(gè).symtab。這里面涉及到兩個(gè)問(wèn)題:
1)各個(gè)object文件合并的順序。這個(gè)問(wèn)題涉及到最終指令和符號的運行地址。最為重要的是,究竟是哪個(gè)section排在最前頭?在A(yíng)RMRAW系統得開(kāi)發(fā)過(guò)程中,這個(gè)最為重要。ARM系統CPU上電后,系統會(huì )自動(dòng)的從0x00000000地址取指令并執行,這個(gè)地址上映射著(zhù)存儲器。這個(gè)動(dòng)作是不可編程的。所以排在最前面的section一定要包含有程序的入口點(diǎn),否則系統無(wú)法正常運行。
2)輸入段與輸出端之間的對應關(guān)系。理論上,任何section,都可以被隨意的映射到一個(gè)輸出段中。一個(gè).datasection是可以與一個(gè).textsection組成輸出一個(gè).text的。當然這樣的動(dòng)作毫無(wú)意義。我們必須告訴linker使用那些section作為輸入,產(chǎn)生一個(gè)輸出section.
以上這兩個(gè)問(wèn)題,都是通過(guò)一個(gè)稱(chēng)為連接腳本的文件控制的。Linker通過(guò)讀取連接腳本,來(lái)決定section從輸入到輸出的映射,設置程序的入口點(diǎn),設置哪個(gè)section應該在整個(gè)可執行文件的頭部等問(wèn)題。
連接腳本還有另外一個(gè)作用,那就是指定每個(gè)section的地址。在section合并完成后,linker將跟據.symtab,對符號進(jìn)行統一的編址,分配一個(gè)絕對的運行時(shí)地址。這個(gè)地址是以section地址作為基地址的。假設.textsection的地址是0x00000000,那么.text里面的符號將以0x00000000這個(gè)地址作為基準地址。指定section地址的工作也是由連接腳本完成。在嵌入式開(kāi)發(fā)中常見(jiàn)的在編譯工程時(shí)需指定的text_base,data_base等參數,最后會(huì )被加入到連接腳本中,從而完成section的地址分配。
以上兩步完成后,linker執行引用符號重定位操作。Linker遍歷.relsection(包括.reltext和.reldata),對于其中的每個(gè)數據項,根據symbol域到.symtab中查出相應的引用的真實(shí)地址(經(jīng)過(guò)上面的地址分配,現在.symtab里面的符號都具有絕對的運行地址),再根據offset域提供的偏移,將這個(gè)地址填入相應的位置上。
至此,符號重定位工作全部完成。Linker刪除用于保存重定位信息的rel.text和rel.datasection,加入一個(gè)segmentheader和一個(gè).initsection。生成可執行的ELF格式的object文件。
Segmentheader保存了用于操作系統內存映射的信息。.initsection包含了一個(gè)_init的函數。程序加載時(shí),操作系統的程序加載器通過(guò)讀取segmentheader,將程序加載到用戶(hù)內存空間,并根據segmentheader里面映射信息,分別將.text段和.data段映射到適當的地址上。然后再調用.init中的_init函數,完成初始化工作。
由于ELF文件具有通用性強的優(yōu)點(diǎn),現在流行的開(kāi)發(fā)模式是,先通過(guò)編譯工具生成ELF文件格式的可執行文件,在使用外部工具,抽離出ELF文件中的相應部分,生成BIN文件。例如著(zhù)名的GNUbootloaderU-Boot,就采用了這種做法,編譯器工具集是GCC,BIN生成工具是elf2bin。ARM公司著(zhù)名的開(kāi)發(fā)環(huán)境ADS,雖然使用的是自家的armcc,和armcpp編譯器,但他們的工作方式卻是與GNUGCC如出一轍。



評論


技術(shù)專(zhuān)區

關(guān)閉
国产精品自在自线亚洲|国产精品无圣光一区二区|国产日产欧洲无码视频|久久久一本精品99久久K精品66|欧美人与动牲交片免费播放
<dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><small id="yhprb"></small><dfn id="yhprb"></dfn><small id="yhprb"><delect id="yhprb"></delect></small><small id="yhprb"></small><small id="yhprb"></small> <delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"></dfn><dfn id="yhprb"></dfn><s id="yhprb"><noframes id="yhprb"><small id="yhprb"><dfn id="yhprb"></dfn></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><small id="yhprb"></small><dfn id="yhprb"><delect id="yhprb"></delect></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn> <small id="yhprb"></small><delect id="yhprb"><strike id="yhprb"></strike></delect><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn><dfn id="yhprb"><s id="yhprb"><strike id="yhprb"></strike></s></dfn><dfn id="yhprb"><s id="yhprb"></s></dfn>