工作经验总结:Hex文件解析

一、Hex文件简介

由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。一般用于MCU程序烧录,可以把hex文件理解为带有地址信息的bin数据的记录集合。(注:烧录时如果使用bin文件则需要指明对应首地址的位置,而使用hex文件则不需要,因为hex文件中包含了对应地址包含的数据内容)

二、Hex文件记录格式与解析

Hex文件记录格式:

RECORD MASK ":"RECLENLOAD OFFSETRECTYPEINFO OR DATACHKSUM
1 Byte1 Byte2 Byte1 Byten Byte1 Byte
  • RECORD MASK:HEX文件的起始格式,文件一开始应该是一个冒号作为起点
  • RECLEN:表示[INFO OR DATA]区域有多少字节的数据长度
  • LOAD OFFSET:表示数据偏移的地址(数据开始记录的偏移地址)
  • RECTYPE:表示该行的Hex文本的类型
    • 00 表示该行记录的是数据(可以理解为bin文件内容)
    • 01 表示该Hex文件结束,一般放在最末尾
    • 02 表示记录的是扩展段地址(数据地址段)
    • 03 表示记录的是开始段地址
    • 04 表示记录的是扩展线性地址
    • 05 表示记录的是起始线性地址(一般认为main函数入口地址)
  • INFO OR DATA:该行的数据或者地址信息
  • CHKSUM:该行的检验和 [该行所有16进制(除了checksum)的累加和S,然后(0x100 - S)& 0xFF]

注意:最常见的Recv type有00、01、04、05

(1)RECTYPE 00 数据标识

 04 2000 00 FECACEFA 4C

04 表示本行有4个字节数据

2000  表示偏移地址为0x2000

FECACEFA  表示本行数据

4C 为该行校验和计算如下:

  • 累加和S =(04 + 20 + 00 + FE + CA + CE + FA)= 0x3B4;
  • 校验和CHKSUM  = (0x100 - S)& 0xFF = 0x4C

(2)RECTYPE 01 文件结束标识

: 00 0000 01 FF

00 表示本行有0个字节数据

0000 表示偏移地址为 0x0000

01  表示Hex文件结束

FF 为该行校验和计算如下:

  • 累加和S =(00 + 00 + 00 + 01)= 0x01;
  • 校验和CHKSUM  = (0x100 - S)& 0xFF = 0xFF

(3)RECTYPE 02 扩展段标识

USBA:用于记录16位扩展段地址的段基址为位4—19(SBA),其中SBA的位0---3为0。位4—19称为上段基地址USBA,再加上LOAD OFFSET就可计算数据偏移量地址。

:02 0000 02 1200 EA  

02 表示本行有2个字节数据

0000 表示偏移地址为 0x0000

02 表示扩展段标识

1200 表示扩展段标识,对应的段地址为0x0001 2000

EA 为该行校验和计算如下:

  • 累加和S =(02 + 00 + 00 + 02 + 12 + 00)= 0x16;
  • 校验和CHKSUM  = (0x100 - S)& 0xFF = 0xEA

 (4)RECTYPE 03 开始段地址

(5)RECTYPE 04 扩展线性地址标识

: 02 0000 04 0005 F5

02 表示本行有2个字节数据

0000 表示偏移地址为 0x0000

04 表示为拓展线性地址

0005 表示扩展线性地址的高16位为0x0005低16位在LOAD OFFSET中为 0x0000,即在下一个04出现前,后续数据记录的基址为 0x0005 0000

F5 为该行校验和计算如下:

  • 累加和S =(02 + 00 + 00 + 04 + 00 + 05)= 0x0B;
  • 校验和CHKSUM  = (0x100 - S)& 0xFF = 0xF5

(6)RECTYPE 05 起始线性地址标识

04 0000 05 00000411 E2

04 表示本行有4个字节数据

0000 表示偏移地址为 0x0000

05 表示起始线性地址标识

00000411 表示目标执行起始地址为0x0000 0411可以在对应map文件中找到

E2 为该行校验和计算如下:

  • 累加和S =(04 + 00 + 00 + 05 + 00 + 00 + 04 + 11)= 0x1E;
  • 校验和CHKSUM  = (0x100 - S)& 0xFF = 0xE2

示例:

:040000050000841162

(7)Recv type 04/00/05/01 简单示例

:020000040005F5
:04200000FECACEFA4C
:0400000500000411E2
:00000001FF

: 02 0000 04 0005 F5 :该行表示后续数据记录的扩展线性地址的基址为 0005 0000

04 2000 00 FECACEFA 4C:表示 0x0005 2000地址起始的数据为FECACEFA

0x0005 20000xFE
0x0005 20010xCA
0x0005 20020xCE
0x0005 20030xFA

04 0000 05 00000411 E2:表示0x0000 0411为main函数的入口地址

: 00 0000 01 FF:表示Hex文件末尾

(8)Recv type 04/02/00 简单示例

:020000040108F1
:020000021200EA 
:0401000090FFAA556D 

:02 0000 04 0108 F1该行表示后续数据记录的扩展线性地址的基址为   0108 0000

:02 0000 02 1200 EA该行表示后续数据记录的扩展段地址的基址为 0001 2000                

:04 0100 00 90FFAA55 6D:该行表示0x0108 0000 +   0x0001 2000 + 0x0100 的起始地址数据为90FFAA55

实际物理地址=扩展线性地址 + 扩展段地址 + 数据偏移地址 = 0x0108 0000 +   0x0001 2000 + 0x0100 = 0x0109 2100

三、Hex文件解析Python代码示例

Hex文件的内容行解析python代码示例:

def _line_analyse(self, line:str):
        # string fliter
        line = line.strip()  # 去除开头与结尾的空格或换行符
        
        # Hex file format
        record_mask    = line[0]
        data_len       = int(line[1:3], 16)
        load_offset    = int(line[3:7], 16)
        recv_type      = int(line[7:9], 16)
        checksum       = int(line[-2:], 16)
        
        # Hex file info string dispose
        DATA_START_INDEX = 9
        DATA_STR_LENGTH  = data_len * 2

        if (record_mask == ":") and (self.is_finished_analyse == False):
            # 数据记录类型
            if (recv_type == 0x00):     
                base_addr = self.address_info_list[-1]
                address = base_addr + load_offset
                
                data_hex_list = []
                for i in range(0, DATA_STR_LENGTH, 2):
                    data_hex = int(line[DATA_START_INDEX + i : DATA_START_INDEX + i + 2], 16)
                    data_hex_list.append(data_hex)

                # checksum 校验和检测
                # 该行所有16进制累加和S, 然后0x100 - S
                checksum_temp = 0
                for i in range(1, len(line) - 2, 2):
                    checksum_temp += int(line[i : i+2], 16)
                checksum_temp = (0x100 - checksum_temp) & 0xFF
                
                # 数据保存
                if checksum_temp == checksum:
                    self.data_dict[address] = data_hex_list
                else:
                    print("checksum_temp:0x{:2x}, checksum:0x{:2x}, line:{:s}".format(checksum_temp, checksum, line))
                    
            # 文件结束类型
            elif(recv_type == 0x01):    
                self.is_finished_analyse = True
            
            # 标识拓展段地址 (Hex86)
            elif(recv_type == 0x02):     
                pass
            
            # 标识开始段地址 (Hex86)
            elif(recv_type == 0x03):
                pass
            
            # 标识扩展线性地址
            elif(recv_type == 0x04):
                address_high_half_word = int(line[DATA_START_INDEX : DATA_START_INDEX + DATA_STR_LENGTH], 16)
                address_low_half_word = load_offset
                address = ((address_high_half_word << 16) | (address_low_half_word)) & 0xFFFFFFFF
                # 补充地址信息
                self.address_info_list.append(address)
                
            # 标识开始线性地址 (main函数入口地址)
            elif(recv_type == 0x05):
                eip_address = int(line[DATA_START_INDEX : DATA_START_INDEX + DATA_STR_LENGTH], 16) + load_offset
                self.main_address = eip_address
        else:
            pass

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

不吃鱼的猫丿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值