HEX BIN文件 分析介绍
生活随笔
收集整理的這篇文章主要介紹了
HEX BIN文件 分析介绍
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
總結:
HEX文件:由一條條具有規定格式、由16進制的數據表示特定特定信息的HEX文本記錄組成的可燒寫文件,每條記錄中的數據包含有地址與要燒寫的數據以及檢驗碼等信息。每條燒寫文本記錄中若包含數據記錄,那么16進制的數據與BIN文件【16進制表示時】是一樣的,HEX每條文本記錄多出來的就是地址與檢驗信息等....
BIN文件,就是直接可以燒寫到存儲器中的二進制文件,程序運行后,對應地址的數據與BIN是一摸一樣的.我們可以打開KEIL軟件,軟件調試時,可以看到,C對應匯編【硬件調試時用的是反匯編】,匯編再對應相應的機器碼,最左邊的存儲空間地址,過來就是對應的機器指令,因為這里的ARM都是Thumb指令所以每一條指令對應的是16位,兩個字節,而ARM指令是32位的,4個字節,BIN文件就是這些機器碼的集合,HEX文件中的數據記錄也是這些機器碼得集合,不過HEX文件中除了這些數據記錄還有地址信息等
截圖從反匯編,紅色部分也是BIN文件的內容
HEX文件截圖
可以從上面的兩幅圖片上的兩種顏色框的對應關系看出其中的關系
Intel HEX文件是記錄文本行的ASCII文本文件,在Intel HEX文件中,每一行是一個HEX記錄,由十六進制數組成的機器碼或者數據常量。 Intel HEX文件經常被用于將程序或數據傳輸存儲到ROM、EPROM,大多數編程器和模擬器使用Intel HEX文件。
???很多編譯器的支持生成HEX格式的燒錄文件,尤其是Keil c。但是編程器能夠下載的往往是BIN格式,因此HEX轉BIN是每個編程器都必須支持的功能。 ??? ???HEX格式文件以行為單位,每行由“:”(0x3a)開始,以回車鍵結束(0x0d,0x0a)。 ???行內的數據都是由兩個字符表示一個16進制字節,比如”01”就表示數0x01;”0a”,就表示0x0a。 ???對于16位的地址,則高位在前低位在后,比如地址0x010a,在HEX格式文件中就表示為字符串”010a”。 ???下面為HEX文件中的一行::10 0000 00 FF0462FF051EFF0A93FF0572FF0A93FF BC ? ???“:”表示一行的開始。 ? ???“:”后的第1,2個字符“10”表示本行包含的數據的長度,這里就是0x10即16個。 ??? ???第3,4,5,6個字符“0000”表示數據存儲的起始地址,這里表示從0x0000地址開始存儲16個數據,其中高位地址在前,低位地址在后。 ? ???第7,8個字符“00”表示數據的類型。該類型總共有以下幾種: 00 ----數據記錄? 01 ----文件結束記錄 02 ----擴展段地址記錄 04 ----擴展線性地址記錄這里就是0x00即為普通數據記錄。 自后的32個字符就是本行包含的數據,每兩個字符表示一個字節數據,總共有16個字節數據跟行首的記錄的長度相一致。 最后兩個字符表示校驗碼。 每個HEX格式的最后一行都是固定為::00000001FF ???以上的信息其實就足夠進行HEX轉BIN格式的程序的編寫。 首先我們只處理數據類型為0x00及0x01的情況。0x02表示對應的存儲地址超過了64K,由于我的編程器只針對64K以下的單片機, 因此在次不處理,0x04也是如此
什么是Intel HEX格式? 回答: Intel HEX文件是記錄文本行的ASCII文本文件,在Intel HEX文件中,每一行是一個HEX記錄 由十六進制數組成的機器碼或者數據常量,Intel HEX文件經常被用于將程序或數據傳輸 存儲到ROM.EPROM,大多數編程器和模擬器使用Intel HEX文件.
記錄格式 一個Intel HEX文件可以包含任意多的十六進制記錄,每條記錄有五個域,下面是一個記錄的格式. :llaaaatt[dd...]cc 每一組字母是獨立的一域,每一個字母是一個十六進制數字,每一域至少由兩個十六進制數字組成,下面是字節的描述. :冒號 是每一條Intel HEX記錄的開始 ll 是這條記錄的長度域,他表示數據(dd)的字節數目. aaaa 是地址域,他表示數據的起始地址<如果是數據記錄,這表示將要燒錄的這條記錄中的數據在EPROM中的偏移地址, 對于不支持擴展段地址和擴展線性地址的,如89C51,這就是此條記錄的起始地址>
tt 這個域表示這條HEX記錄的類型,他有可能是下面這幾種類型 00 ----數據記錄? 01 ----文件結束記錄 02 ----擴展段地址記錄 04 ----擴展線性地址記錄
dd 是數據域,表示一個字節的數據,一個記錄可能有多個數據字節,字節數目可以 查看ll域的說明
cc 是效驗和域,表示記錄的效驗和,計算方法是將本條記錄冒號開始的所有字母對 <不包括本效驗字和冒號> 所表示的十六進制數字 <一對字母表示一個十六進制數,這樣的一個十六進制數為一個字節> 都加起來然后模除256得到的余數 最后求出余數的補碼即是本效驗字節cc. <例如: :0300000002005E9D cc=0x01+NOT((0x03+0x00+0x00+0x00+0x02+0x00+0x5E)%0x100)=0x01+0x9C=0x9D
C語言描述: UCHAR cc; cc=(UCHAR)~(0x03+0x00+0x00+0x00+0x02+0x00+0x5E); cc++; > 數據記錄
Intel HEX文件由若干個數據記錄組成,一個數據記錄以一個回車和一個換行結束 <回車為0x0d換行為0x0a>
比如下面的一條數據記錄 :10246200464C5549442050524F46494C4500464C33
10 是此行記錄數據的字節數目 2462 是數據在內存<將要燒寫的eprom地址>中的起始地址 00 是記錄類型00(是一個數據記錄) 464C 到 464C 是數據 33 是此行記錄的效驗和
擴展線性地址記錄(HEX386) 擴展線性地址記錄也可稱為 32位地址記錄 和 HEX386記錄,這個紀錄包含高16(16-31位)位數據地址,這種擴展的線性記錄總是有兩個字節數據,像下面這樣:
:02000004FFFFFC 02 是記錄的數據字節數目 0000 是地址域這在擴展地址記錄中總是0000 04 是記錄類型04(擴展地址記錄) FFFF 是高16位地址 FC 是記錄效驗和,計算方法如下: 01h + NOT(02h + 00h + 00h + 04h + FFh + FFh)
當一個擴展線性地址記錄被讀到后,擴展線性地址記錄的數據區域將被保存 并應用到后面從Intel HEX文件中讀出的記錄,這個擴展線性記錄一直有效, 直到讀到下一個擴展線性記錄.
絕對內存地址 = 數據記錄中的地址 + 移位后的擴展線性地址
下面舉例說明這個過程
從數據記錄的地址域得到地址 2462 從擴展線性地址記錄的地址域得到地址 FFFF 絕對內存地址 FFFF2462
擴展段地址記錄 (HEX86)?
擴展段地址記錄也被稱為 HEX86記錄, 包含 4-19位的數據地址段, 這個擴展段地址記錄總是有兩字節數據,如下:
:020000021200EA 02 是 記錄中的數據字節數目 0000 是地址域,在擴展段地址記錄中,這個域總是0000 02 是記錄類型02(擴展段地址的標示) 1200 是該段的地址 EA 是效驗和 計算如下: 01h + NOT(02h + 00h + 00h + 02h + 12h + 00h).
當擴展段地址記錄被讀后,擴展段地址將被存儲并應用到以后從Intel HEX文件讀出的記錄,這個段地址一直有效直到讀到下一個擴展段地址記錄
絕對內存地址 = 數據記錄中的地址 + 移位后的擴展段地址
數據記錄中的地址域 移位后擴展段地址記錄中的地址域
下面舉例說明這個過程
從數據記錄的地址域得到地址 2 4 6 2 從擴展段地址記錄的地址域得到地址 1 2 0 0 絕對內存地址 0 0 0 1 4 4 6 2
文件結束記錄(EOF) 一個Intel HEX文件必須有一個文件結束記錄,這個記錄的類型域必須是01, 一個EOF記錄總是這樣: :00000001FF 00是記錄中數據字節的數目 0000這個地址對于EOF記錄來說無任何意義 01記錄類型是01(文件結束記錄標示) FF是效驗和計算如下 01h + NOT(00h + 00h + 00h + 01h). ========================
總結
形如 :BBAAAATTHHHH...HHHHCC
BB: Byte AAAA:數據記錄的開始地址,高位在前,地位在后 因為這個格式只支持8bits,地址被倍乘 所以,為了得到實際的PIC的地址,需要將 地址除以2 TT: Type 00 數據記錄 01 記錄結束 04 擴展地址記錄(表示32位地址的前綴,當然這種只能在 INHX32) HHHH:一個字(Word)的數據記錄,高Byte在前,低Byte在后 TT之后,總共有 BB/2 個字 的數據 CC: 一個Byte的CheckSum
因為PIC16F873A只有4K的程序空間
所以,不會有 TT=04的 Linear Address Record
而Bin文件是最純粹的二進制機器代碼,沒有格式,或者說是"順序格式"按assembly code順序翻譯成binary machine code. 由于分析出來Hex文件中的數據域ASCII碼表示的十六進制與二進制一一對應,而且我公司DSP又是16位的,以一個word為最小單位, 所以四個十六進制ASCII碼代表一條機器指令單位或者地址.借于上面分析,編寫了工具代碼. 大體原理是用fscanf函數在每行的數據域讀入四個 ASCII碼,以短整形(short int 16bit)形式儲存,在把這個短整形變量順序fwrite到文件流中去即可.?
舉一例說明:? 表1? ORG 0000H? LJMP START? ORG 040H? START:? MOV SP,#5FH ;設堆棧? LOOP:? NOP? LJMP LOOP ;循環? END ;結束? 表2? :03000000020040BB? :0700400075815F000200431F? 表3 ? 02 00 40 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF? FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF? FF FF FF FF FF FF FF FF FF FF FF FF 75 81 5F 00 02 00 43? 表1為源程序,表2是匯編后得到的HEX文件,表3是由HEX文件轉換成的目標文件,也就是最終寫入EPROM的文件,它由編程器轉換得到, 也可以由 HEXBIN一類的程序轉換得到。學過手工匯編者應當不難找出表3與表1的一一對應關系, 值得注意的是從02 00 40后開始的一長串‘FF’,直到75 81,這是由于偽指令:ORG 040H造成的結果。?
/ copy from:http://tieba.baidu.com/f?kz=271526661?
#include <stdio.h> #include <stdlib.h> #include <string.h>
FILE *fp_read; ??????????????? FILE *fp_write; ????????????? ?????? ?????? unsigned long start_adr; ????? unsigned short cur_base; ????? unsigned short cur_offset; ???
unsigned char read_buf[16]; unsigned char write_buf[48];
void calc_start_adr (char *buf) { ?????unsigned int len; ??? ?????len = strlen(buf); ??? ?????if ((buf[len-1] != 'k') && (buf[len-1] != 'K')) { ?????????printf ("Invalid argument.\n"); ?????????exit (-1); ?????} ??? ?????buf[len-1] = 0; ??? ?????start_adr = atoi (buf); ?????start_adr = start_adr * 1024; ?????cur_base = ???start_adr >> 16;? ?????cur_offset = (unsigned short)start_adr; }
void start_convert (void) { ?????unsigned char cnt; ?????unsigned char read_num; ?????unsigned char cksum, highc, lowc; ??? ???? ?????highc = cur_base >> 8; ?????lowc = (unsigned char)cur_base; ?????cksum = 2 + 4 + highc + lowc; ?????cksum = 0xFF - cksum; ?????cksum = cksum + 1; ?????sprintf (write_buf, ":02000004xx", cur_base, cksum); ?????write_buf[15] = 0x0D; write_buf[16] = 0x0A;? ?????fwrite (write_buf, 1, 17, fp_write); ??? ?????read_num = fread (read_buf, 1, 16, fp_read); ?????while (read_num == 16) { ???????? ?????????highc = cur_offset >> 8; ?????????lowc = (unsigned char)cur_offset; ?????????cksum = 0x10 + highc + lowc; ?????????for (cnt=0; cnt<16; cnt++) { ?????????????cksum += read_buf[cnt]; ?????????} ?????????cksum = 0xFF - cksum; ?????????cksum = cksum + 1; ??????? ?????????sprintf (write_buf, ":10xx00xxxxxxxxxxxxxxxxx",? ?????????????????highc, lowc, ?????????????????read_buf[0], read_buf[1], read_buf[2], read_buf[3],? ?????????????????read_buf[4], read_buf[5], read_buf[6], read_buf[7],? ?????????????????read_buf[8], read_buf[9], read_buf[10], read_buf[11],? ?????????????????read_buf[12], read_buf[13], read_buf[14], read_buf[15],? ?????????????????cksum); ?????????write_buf[43] = 0x0D; write_buf[44] = 0x0A; ?????????fwrite (write_buf, 1, 45, fp_write); ??????? ???????? ?????????if (cur_offset == 65520) { ?????????????cur_offset = 0; ?????????????cur_base ++; ?????????????highc = cur_base >> 8; ?????????????lowc = (unsigned char)cur_base; ?????????????cksum = 2 + 4 + highc + lowc; ?????????????cksum = 0xFF - cksum; ?????????????cksum = cksum + 1; ?????????????sprintf (write_buf, ":02000004xx", cur_base, cksum); ?????????????write_buf[15] = 0x0D; write_buf[16] = 0x0A;? ?????????????fwrite (write_buf, 1, 17, fp_write); ?????????} else { ?????????????cur_offset += 16; ?????????} ??????? ?????????read_num = fread (read_buf,1,16,fp_read); ?????} ??? ???? ?????if (read_num) { ?????????highc = cur_offset >> 8; ?????????lowc = (unsigned char)cur_offset; ?????????cksum = read_num + highc + lowc; ?????????for (cnt=0; cnt<read_num; cnt++) { ?????????????cksum += read_buf[cnt]; ?????????} ?????????cksum = 0xFF - cksum; ?????????cksum = cksum + 1; ??????? ?????????sprintf (write_buf, ":xxx00", read_num, highc, lowc); ?????????for (cnt=0; cnt<read_num; cnt++) { ?????????????sprintf (&write_buf[9 + cnt * 2], "x", read_buf[cnt]); ?????????} ?????????sprintf (&write_buf[9 + cnt * 2], "x", cksum); ?????????write_buf[11 + read_num * 2] = 0x0D; ?????????write_buf[12 + read_num * 2] = 0x0A; ?????????fwrite (write_buf, 1, 13 + read_num * 2, fp_write); ?????} ??? ???? ?????sprintf (write_buf, ":00000001FF"); ?????write_buf[11] = 0x0D; write_buf[12] = 0x0A; ?????fwrite (write_buf, 1, 13, fp_write); }
int main (int argc, char *argv[]) { ??? ?????if (argc != 4) { ?????????printf ("Usage : %s -b address filename.xxx\n", argv[0]); ?????????printf ("-b : indicate the starting address convert to.\n"); ?????????printf ("address : starting address.\n"); ?????????printf ("filename.xxx : file to be converted.\n"); ?????????printf ("output : ???filename.hex\n"); ?????????printf ("example : %s -b 64k rom.bin\n", argv[0]); ?????????return -1; ?????} ??? ?????if (strcmp (argv[1], "-b")) { ?????????printf ("Invalid argument.\n"); ?????????return -1; ?????}; ??? ?????fp_read = fopen (argv[3], "rb"); ?????if (fp_read == NULL) { ?????????printf ("Can't open file %s", argv[3]); ?????????return -1; ?????}
?????fp_write = fopen ("rom.hex", "w"); ?????if (fp_write == NULL) { ?????????printf ("Can't create file rom.hex"); ?????????return -1; ?????} ??? ?????calc_start_adr (argv[2]); ?????start_convert (); ??? ?????fclose (fp_read); ?????fclose (fp_write); ??? ?????printf("Convert Seccessfully!\n"); ??? ?????return 0; }?
簡單介紹一下這2種文件格式的區別:
1 - HEX文件是包括地址信息的,而BIN文件格式只包括了數據本身 ?????????在燒寫或下載HEX文件的時候,一般都不需要用戶指定地址,因為HEX文件內部的信息已經包括了地址。而燒寫BIN ?????????文件的時候,用戶是一定需要指定地址信息的。 ???????? ???????? 3 - BIN文件格式 ?????????對二進制文件而言,其實沒有”格式”。文件只是包括了純粹的二進制數據。 ???????? ???????? 4 - HEX文件格式 ?????????HEX文件都是由記錄(RECORD)組成的。在HEX文件里面,每一行代表一個記錄。記錄的基本格式為: ?????????+---------------------------------------------------------------+ ?????????| ???RECORD ??| RECLEN | ??LOAD ??| RECTYPE | INFO or DATA | CHKSUM | ?????????| ??MARK ':' | ????????| OFFSET | ?????????| ??????????????| ????????| ?????????+---------------------------------------------------------------+ ?????????| ??1-byte ???| 1-byte | 2-byte | 1-byte ??| ????n-byte ????| 1-byte | ?????????+---------------------------------------------------------------+ ???????? ?????????記錄類型包括: ?????????'00' Data Rrecord:用來記錄數據,HEX文件的大部分記錄都是數據記錄 ?????????'01' End of File Record: 用來標識文件結束,放在文件的最后,標識HEX文件的結尾 ?????????'04' Extended Linear Address Record: 用來標識擴展線性地址的記錄 ?????????'02' Extended Segment Address Record: 用來標識擴展段地址的記錄 ???????? ?????????在上面的后2種記錄,都是用來提供地址信息的。每次碰到這2個記錄的時候,都可以根據記錄計算出一個“基”地址。 ?????????對于后面的數據記錄,計算地址的時候,都是以這些“基”地址為基礎的。 ???????? ?????????數據記錄的具體格式: ?????????+---------------------------------------------------------------+ ?????????| ???RECORD ??| RECLEN | ??LOAD ??| RECTYPE | INFO or DATA | CHKSUM | ?????????| ??MARK ':' | ????????| OFFSET | ??'00' ???| ??????????????| ????????| ?????????+---------------------------------------------------------------+ ?????????| ??1-byte ???| 1-byte | 2-byte | 1-byte ??| ????n-byte ????| 1-byte | ?????????+---------------------------------------------------------------+ ???????? ???????? ?????????看個例子: ????????:020000040000FA ????????:10000400FF00A0E314209FE5001092E5011092E5A3 ????????:00000001FF ???????? ?????? ????????對上面的HEX文件進行分析: ????????第1條記錄的長度為02,LOAD OFFSET為0000,RECTYPE為04,說明該記錄為擴展段地址記錄。數據為0000,校驗和為 ????????FA。從這個記錄的長度和數據,我們可以計算出一個基地址,這個地址為0X0000。后面的數據記錄都以這個地址為基 ????????地址。 ????????第2條記錄的長度為10(16),LOAD OFFSET為0004,RECTYPE為00,說明該記錄為數據記錄。 ????????數據為FF00A0E314209FE5001092E5011092E5,共16個BYTE。這個記錄的校驗和為A3。此時的基地址為0X0000,加上OFFSET, ????????這個記錄里的16BYTE的數據的起始地址就是0x0000 + 0x0004 = 0x0004. ????????第3條記錄的長度為00,LOAD OFFSET為0000,TYPE = 01,校驗和為FF。說明這個是一個END OF FILE RECORD,標識 ????????文件的結尾。 ?????? ????????在上面這個例子里,實際的數據只有16個BYTE:FF00A0E314209FE5001092E5011092E5,其起始地址為0x4 ??????????
4 - HEX文件和BIN文件大小有區別 ?????HEX文件是用ASCII來表示二進制的數值。例如一般8-BIT的二進制數值0x3F,用ASCII來表示就需要分別表示字符'3' ?????和字符'F',每個字符需要一個BYTE,所以HEX文件需要 > 2倍的空間。 ?????對一個BIN文件而言,你查看文件的大小就可以知道文件包括的數據的實際大小。而對HEX文件而言,你看到的文件 ?????大小并不是實際的數據的大小。一是因為HEX文件是用ASCII來表示數據,二是因為HEX文件本身還包括別的附加信息。? 本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/studyvcmfc/archive/2009/05/30/4225282.aspx
????????Thumb指令可以看做是ARM指令壓縮形式的子集,是針對代碼密度【1】的問題而提出的,它具有16為的代碼密度。Thumb不是一個完整的體系結構,不能指望處理程序只執行Thumb指令而不支持ARM指令集。因此,Thumb指令只需要支持通用功能,必要時,可借助完善的ARM指令集,例如:所有異常自動進入ARM狀態。
???????在編寫Thumb指令時,先要使用偽指令CODE16聲明,而且在ARM指令中要使用BX指令跳轉到Thumb指令,以切換處理器狀態。編寫ARM指令時,可使用偽指令CODE32聲明。
??????代碼密度:單位存儲空間中包含的指令的個數。例如
??????????????ARM指令是32位的,而Thumb指令時16位的,如果在1K的存儲空間中,可以放32條ARM指令,就可以放64條Thumb指令,因此在存放Thunb指令時,代碼密度高。
arm存儲格式有小端結尾(低字節存儲在低位,即由小到大)、大端結尾(最高字節存儲在低位,即由大到小)。arm存儲以字節為單位,地址空間為2^32個字節共4G空間。arm存儲訪問由對齊訪問和非對齊訪問。arm指令長度固定為一個字長,即32位
截圖從反匯編,紅色部分也是BIN文件的內容
HEX文件截圖
可以從上面的兩幅圖片上的兩種顏色框的對應關系看出其中的關系
Intel HEX文件是記錄文本行的ASCII文本文件,在Intel HEX文件中,每一行是一個HEX記錄,由十六進制數組成的機器碼或者數據常量。 Intel HEX文件經常被用于將程序或數據傳輸存儲到ROM、EPROM,大多數編程器和模擬器使用Intel HEX文件。
???很多編譯器的支持生成HEX格式的燒錄文件,尤其是Keil c。但是編程器能夠下載的往往是BIN格式,因此HEX轉BIN是每個編程器都必須支持的功能。 ??? ???HEX格式文件以行為單位,每行由“:”(0x3a)開始,以回車鍵結束(0x0d,0x0a)。 ???行內的數據都是由兩個字符表示一個16進制字節,比如”01”就表示數0x01;”0a”,就表示0x0a。 ???對于16位的地址,則高位在前低位在后,比如地址0x010a,在HEX格式文件中就表示為字符串”010a”。 ???下面為HEX文件中的一行::10 0000 00 FF0462FF051EFF0A93FF0572FF0A93FF BC ? ???“:”表示一行的開始。 ? ???“:”后的第1,2個字符“10”表示本行包含的數據的長度,這里就是0x10即16個。 ??? ???第3,4,5,6個字符“0000”表示數據存儲的起始地址,這里表示從0x0000地址開始存儲16個數據,其中高位地址在前,低位地址在后。 ? ???第7,8個字符“00”表示數據的類型。該類型總共有以下幾種: 00 ----數據記錄? 01 ----文件結束記錄 02 ----擴展段地址記錄 04 ----擴展線性地址記錄這里就是0x00即為普通數據記錄。 自后的32個字符就是本行包含的數據,每兩個字符表示一個字節數據,總共有16個字節數據跟行首的記錄的長度相一致。 最后兩個字符表示校驗碼。 每個HEX格式的最后一行都是固定為::00000001FF ???以上的信息其實就足夠進行HEX轉BIN格式的程序的編寫。 首先我們只處理數據類型為0x00及0x01的情況。0x02表示對應的存儲地址超過了64K,由于我的編程器只針對64K以下的單片機, 因此在次不處理,0x04也是如此
什么是Intel HEX格式? 回答: Intel HEX文件是記錄文本行的ASCII文本文件,在Intel HEX文件中,每一行是一個HEX記錄 由十六進制數組成的機器碼或者數據常量,Intel HEX文件經常被用于將程序或數據傳輸 存儲到ROM.EPROM,大多數編程器和模擬器使用Intel HEX文件.
記錄格式 一個Intel HEX文件可以包含任意多的十六進制記錄,每條記錄有五個域,下面是一個記錄的格式. :llaaaatt[dd...]cc 每一組字母是獨立的一域,每一個字母是一個十六進制數字,每一域至少由兩個十六進制數字組成,下面是字節的描述. :冒號 是每一條Intel HEX記錄的開始 ll 是這條記錄的長度域,他表示數據(dd)的字節數目. aaaa 是地址域,他表示數據的起始地址<如果是數據記錄,這表示將要燒錄的這條記錄中的數據在EPROM中的偏移地址, 對于不支持擴展段地址和擴展線性地址的,如89C51,這就是此條記錄的起始地址>
tt 這個域表示這條HEX記錄的類型,他有可能是下面這幾種類型 00 ----數據記錄? 01 ----文件結束記錄 02 ----擴展段地址記錄 04 ----擴展線性地址記錄
dd 是數據域,表示一個字節的數據,一個記錄可能有多個數據字節,字節數目可以 查看ll域的說明
cc 是效驗和域,表示記錄的效驗和,計算方法是將本條記錄冒號開始的所有字母對 <不包括本效驗字和冒號> 所表示的十六進制數字 <一對字母表示一個十六進制數,這樣的一個十六進制數為一個字節> 都加起來然后模除256得到的余數 最后求出余數的補碼即是本效驗字節cc. <例如: :0300000002005E9D cc=0x01+NOT((0x03+0x00+0x00+0x00+0x02+0x00+0x5E)%0x100)=0x01+0x9C=0x9D
C語言描述: UCHAR cc; cc=(UCHAR)~(0x03+0x00+0x00+0x00+0x02+0x00+0x5E); cc++; > 數據記錄
Intel HEX文件由若干個數據記錄組成,一個數據記錄以一個回車和一個換行結束 <回車為0x0d換行為0x0a>
比如下面的一條數據記錄 :10246200464C5549442050524F46494C4500464C33
10 是此行記錄數據的字節數目 2462 是數據在內存<將要燒寫的eprom地址>中的起始地址 00 是記錄類型00(是一個數據記錄) 464C 到 464C 是數據 33 是此行記錄的效驗和
擴展線性地址記錄(HEX386) 擴展線性地址記錄也可稱為 32位地址記錄 和 HEX386記錄,這個紀錄包含高16(16-31位)位數據地址,這種擴展的線性記錄總是有兩個字節數據,像下面這樣:
:02000004FFFFFC 02 是記錄的數據字節數目 0000 是地址域這在擴展地址記錄中總是0000 04 是記錄類型04(擴展地址記錄) FFFF 是高16位地址 FC 是記錄效驗和,計算方法如下: 01h + NOT(02h + 00h + 00h + 04h + FFh + FFh)
當一個擴展線性地址記錄被讀到后,擴展線性地址記錄的數據區域將被保存 并應用到后面從Intel HEX文件中讀出的記錄,這個擴展線性記錄一直有效, 直到讀到下一個擴展線性記錄.
絕對內存地址 = 數據記錄中的地址 + 移位后的擴展線性地址
下面舉例說明這個過程
從數據記錄的地址域得到地址 2462 從擴展線性地址記錄的地址域得到地址 FFFF 絕對內存地址 FFFF2462
擴展段地址記錄 (HEX86)?
擴展段地址記錄也被稱為 HEX86記錄, 包含 4-19位的數據地址段, 這個擴展段地址記錄總是有兩字節數據,如下:
:020000021200EA 02 是 記錄中的數據字節數目 0000 是地址域,在擴展段地址記錄中,這個域總是0000 02 是記錄類型02(擴展段地址的標示) 1200 是該段的地址 EA 是效驗和 計算如下: 01h + NOT(02h + 00h + 00h + 02h + 12h + 00h).
當擴展段地址記錄被讀后,擴展段地址將被存儲并應用到以后從Intel HEX文件讀出的記錄,這個段地址一直有效直到讀到下一個擴展段地址記錄
絕對內存地址 = 數據記錄中的地址 + 移位后的擴展段地址
數據記錄中的地址域 移位后擴展段地址記錄中的地址域
下面舉例說明這個過程
從數據記錄的地址域得到地址 2 4 6 2 從擴展段地址記錄的地址域得到地址 1 2 0 0 絕對內存地址 0 0 0 1 4 4 6 2
文件結束記錄(EOF) 一個Intel HEX文件必須有一個文件結束記錄,這個記錄的類型域必須是01, 一個EOF記錄總是這樣: :00000001FF 00是記錄中數據字節的數目 0000這個地址對于EOF記錄來說無任何意義 01記錄類型是01(文件結束記錄標示) FF是效驗和計算如下 01h + NOT(00h + 00h + 00h + 01h). ========================
總結
形如 :BBAAAATTHHHH...HHHHCC
BB: Byte AAAA:數據記錄的開始地址,高位在前,地位在后 因為這個格式只支持8bits,地址被倍乘 所以,為了得到實際的PIC的地址,需要將 地址除以2 TT: Type 00 數據記錄 01 記錄結束 04 擴展地址記錄(表示32位地址的前綴,當然這種只能在 INHX32) HHHH:一個字(Word)的數據記錄,高Byte在前,低Byte在后 TT之后,總共有 BB/2 個字 的數據 CC: 一個Byte的CheckSum
因為PIC16F873A只有4K的程序空間
所以,不會有 TT=04的 Linear Address Record
而Bin文件是最純粹的二進制機器代碼,沒有格式,或者說是"順序格式"按assembly code順序翻譯成binary machine code. 由于分析出來Hex文件中的數據域ASCII碼表示的十六進制與二進制一一對應,而且我公司DSP又是16位的,以一個word為最小單位, 所以四個十六進制ASCII碼代表一條機器指令單位或者地址.借于上面分析,編寫了工具代碼. 大體原理是用fscanf函數在每行的數據域讀入四個 ASCII碼,以短整形(short int 16bit)形式儲存,在把這個短整形變量順序fwrite到文件流中去即可.?
舉一例說明:? 表1? ORG 0000H? LJMP START? ORG 040H? START:? MOV SP,#5FH ;設堆棧? LOOP:? NOP? LJMP LOOP ;循環? END ;結束? 表2? :03000000020040BB? :0700400075815F000200431F? 表3 ? 02 00 40 FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF? FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF? FF FF FF FF FF FF FF FF FF FF FF FF 75 81 5F 00 02 00 43? 表1為源程序,表2是匯編后得到的HEX文件,表3是由HEX文件轉換成的目標文件,也就是最終寫入EPROM的文件,它由編程器轉換得到, 也可以由 HEXBIN一類的程序轉換得到。學過手工匯編者應當不難找出表3與表1的一一對應關系, 值得注意的是從02 00 40后開始的一長串‘FF’,直到75 81,這是由于偽指令:ORG 040H造成的結果。?
/ copy from:http://tieba.baidu.com/f?kz=271526661?
#include <stdio.h> #include <stdlib.h> #include <string.h>
FILE *fp_read; ??????????????? FILE *fp_write; ????????????? ?????? ?????? unsigned long start_adr; ????? unsigned short cur_base; ????? unsigned short cur_offset; ???
unsigned char read_buf[16]; unsigned char write_buf[48];
void calc_start_adr (char *buf) { ?????unsigned int len; ??? ?????len = strlen(buf); ??? ?????if ((buf[len-1] != 'k') && (buf[len-1] != 'K')) { ?????????printf ("Invalid argument.\n"); ?????????exit (-1); ?????} ??? ?????buf[len-1] = 0; ??? ?????start_adr = atoi (buf); ?????start_adr = start_adr * 1024; ?????cur_base = ???start_adr >> 16;? ?????cur_offset = (unsigned short)start_adr; }
void start_convert (void) { ?????unsigned char cnt; ?????unsigned char read_num; ?????unsigned char cksum, highc, lowc; ??? ???? ?????highc = cur_base >> 8; ?????lowc = (unsigned char)cur_base; ?????cksum = 2 + 4 + highc + lowc; ?????cksum = 0xFF - cksum; ?????cksum = cksum + 1; ?????sprintf (write_buf, ":02000004xx", cur_base, cksum); ?????write_buf[15] = 0x0D; write_buf[16] = 0x0A;? ?????fwrite (write_buf, 1, 17, fp_write); ??? ?????read_num = fread (read_buf, 1, 16, fp_read); ?????while (read_num == 16) { ???????? ?????????highc = cur_offset >> 8; ?????????lowc = (unsigned char)cur_offset; ?????????cksum = 0x10 + highc + lowc; ?????????for (cnt=0; cnt<16; cnt++) { ?????????????cksum += read_buf[cnt]; ?????????} ?????????cksum = 0xFF - cksum; ?????????cksum = cksum + 1; ??????? ?????????sprintf (write_buf, ":10xx00xxxxxxxxxxxxxxxxx",? ?????????????????highc, lowc, ?????????????????read_buf[0], read_buf[1], read_buf[2], read_buf[3],? ?????????????????read_buf[4], read_buf[5], read_buf[6], read_buf[7],? ?????????????????read_buf[8], read_buf[9], read_buf[10], read_buf[11],? ?????????????????read_buf[12], read_buf[13], read_buf[14], read_buf[15],? ?????????????????cksum); ?????????write_buf[43] = 0x0D; write_buf[44] = 0x0A; ?????????fwrite (write_buf, 1, 45, fp_write); ??????? ???????? ?????????if (cur_offset == 65520) { ?????????????cur_offset = 0; ?????????????cur_base ++; ?????????????highc = cur_base >> 8; ?????????????lowc = (unsigned char)cur_base; ?????????????cksum = 2 + 4 + highc + lowc; ?????????????cksum = 0xFF - cksum; ?????????????cksum = cksum + 1; ?????????????sprintf (write_buf, ":02000004xx", cur_base, cksum); ?????????????write_buf[15] = 0x0D; write_buf[16] = 0x0A;? ?????????????fwrite (write_buf, 1, 17, fp_write); ?????????} else { ?????????????cur_offset += 16; ?????????} ??????? ?????????read_num = fread (read_buf,1,16,fp_read); ?????} ??? ???? ?????if (read_num) { ?????????highc = cur_offset >> 8; ?????????lowc = (unsigned char)cur_offset; ?????????cksum = read_num + highc + lowc; ?????????for (cnt=0; cnt<read_num; cnt++) { ?????????????cksum += read_buf[cnt]; ?????????} ?????????cksum = 0xFF - cksum; ?????????cksum = cksum + 1; ??????? ?????????sprintf (write_buf, ":xxx00", read_num, highc, lowc); ?????????for (cnt=0; cnt<read_num; cnt++) { ?????????????sprintf (&write_buf[9 + cnt * 2], "x", read_buf[cnt]); ?????????} ?????????sprintf (&write_buf[9 + cnt * 2], "x", cksum); ?????????write_buf[11 + read_num * 2] = 0x0D; ?????????write_buf[12 + read_num * 2] = 0x0A; ?????????fwrite (write_buf, 1, 13 + read_num * 2, fp_write); ?????} ??? ???? ?????sprintf (write_buf, ":00000001FF"); ?????write_buf[11] = 0x0D; write_buf[12] = 0x0A; ?????fwrite (write_buf, 1, 13, fp_write); }
int main (int argc, char *argv[]) { ??? ?????if (argc != 4) { ?????????printf ("Usage : %s -b address filename.xxx\n", argv[0]); ?????????printf ("-b : indicate the starting address convert to.\n"); ?????????printf ("address : starting address.\n"); ?????????printf ("filename.xxx : file to be converted.\n"); ?????????printf ("output : ???filename.hex\n"); ?????????printf ("example : %s -b 64k rom.bin\n", argv[0]); ?????????return -1; ?????} ??? ?????if (strcmp (argv[1], "-b")) { ?????????printf ("Invalid argument.\n"); ?????????return -1; ?????}; ??? ?????fp_read = fopen (argv[3], "rb"); ?????if (fp_read == NULL) { ?????????printf ("Can't open file %s", argv[3]); ?????????return -1; ?????}
?????fp_write = fopen ("rom.hex", "w"); ?????if (fp_write == NULL) { ?????????printf ("Can't create file rom.hex"); ?????????return -1; ?????} ??? ?????calc_start_adr (argv[2]); ?????start_convert (); ??? ?????fclose (fp_read); ?????fclose (fp_write); ??? ?????printf("Convert Seccessfully!\n"); ??? ?????return 0; }?
簡單介紹一下這2種文件格式的區別:
1 - HEX文件是包括地址信息的,而BIN文件格式只包括了數據本身 ?????????在燒寫或下載HEX文件的時候,一般都不需要用戶指定地址,因為HEX文件內部的信息已經包括了地址。而燒寫BIN ?????????文件的時候,用戶是一定需要指定地址信息的。 ???????? ???????? 3 - BIN文件格式 ?????????對二進制文件而言,其實沒有”格式”。文件只是包括了純粹的二進制數據。 ???????? ???????? 4 - HEX文件格式 ?????????HEX文件都是由記錄(RECORD)組成的。在HEX文件里面,每一行代表一個記錄。記錄的基本格式為: ?????????+---------------------------------------------------------------+ ?????????| ???RECORD ??| RECLEN | ??LOAD ??| RECTYPE | INFO or DATA | CHKSUM | ?????????| ??MARK ':' | ????????| OFFSET | ?????????| ??????????????| ????????| ?????????+---------------------------------------------------------------+ ?????????| ??1-byte ???| 1-byte | 2-byte | 1-byte ??| ????n-byte ????| 1-byte | ?????????+---------------------------------------------------------------+ ???????? ?????????記錄類型包括: ?????????'00' Data Rrecord:用來記錄數據,HEX文件的大部分記錄都是數據記錄 ?????????'01' End of File Record: 用來標識文件結束,放在文件的最后,標識HEX文件的結尾 ?????????'04' Extended Linear Address Record: 用來標識擴展線性地址的記錄 ?????????'02' Extended Segment Address Record: 用來標識擴展段地址的記錄 ???????? ?????????在上面的后2種記錄,都是用來提供地址信息的。每次碰到這2個記錄的時候,都可以根據記錄計算出一個“基”地址。 ?????????對于后面的數據記錄,計算地址的時候,都是以這些“基”地址為基礎的。 ???????? ?????????數據記錄的具體格式: ?????????+---------------------------------------------------------------+ ?????????| ???RECORD ??| RECLEN | ??LOAD ??| RECTYPE | INFO or DATA | CHKSUM | ?????????| ??MARK ':' | ????????| OFFSET | ??'00' ???| ??????????????| ????????| ?????????+---------------------------------------------------------------+ ?????????| ??1-byte ???| 1-byte | 2-byte | 1-byte ??| ????n-byte ????| 1-byte | ?????????+---------------------------------------------------------------+ ???????? ???????? ?????????看個例子: ????????:020000040000FA ????????:10000400FF00A0E314209FE5001092E5011092E5A3 ????????:00000001FF ???????? ?????? ????????對上面的HEX文件進行分析: ????????第1條記錄的長度為02,LOAD OFFSET為0000,RECTYPE為04,說明該記錄為擴展段地址記錄。數據為0000,校驗和為 ????????FA。從這個記錄的長度和數據,我們可以計算出一個基地址,這個地址為0X0000。后面的數據記錄都以這個地址為基 ????????地址。 ????????第2條記錄的長度為10(16),LOAD OFFSET為0004,RECTYPE為00,說明該記錄為數據記錄。 ????????數據為FF00A0E314209FE5001092E5011092E5,共16個BYTE。這個記錄的校驗和為A3。此時的基地址為0X0000,加上OFFSET, ????????這個記錄里的16BYTE的數據的起始地址就是0x0000 + 0x0004 = 0x0004. ????????第3條記錄的長度為00,LOAD OFFSET為0000,TYPE = 01,校驗和為FF。說明這個是一個END OF FILE RECORD,標識 ????????文件的結尾。 ?????? ????????在上面這個例子里,實際的數據只有16個BYTE:FF00A0E314209FE5001092E5011092E5,其起始地址為0x4 ??????????
4 - HEX文件和BIN文件大小有區別 ?????HEX文件是用ASCII來表示二進制的數值。例如一般8-BIT的二進制數值0x3F,用ASCII來表示就需要分別表示字符'3' ?????和字符'F',每個字符需要一個BYTE,所以HEX文件需要 > 2倍的空間。 ?????對一個BIN文件而言,你查看文件的大小就可以知道文件包括的數據的實際大小。而對HEX文件而言,你看到的文件 ?????大小并不是實際的數據的大小。一是因為HEX文件是用ASCII來表示數據,二是因為HEX文件本身還包括別的附加信息。? 本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/studyvcmfc/archive/2009/05/30/4225282.aspx
總結
以上是生活随笔為你收集整理的HEX BIN文件 分析介绍的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 前端学习(604):编程语言
- 下一篇: 在网管员世界上发表文章