Hex文件解析

本文详细介绍了Hex文件的基本概念,包括其记录格式、各类型RECTYPE的作用,并提供了Python代码示例来解析Hex文件内容,包括数据、地址和校验和的处理。
摘要由CSDN通过智能技术生成

一、Hex文件简介

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

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

Hex文件记录格式:

  • 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

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

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

(8)Recv type 04/02/00 简单示例
  1. :020000040108F1

  2. :020000021200EA 

  3. :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

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
解析hex文件的代码可以分为以下几个步骤: 1. 打开hex文件,读取数据 ``` file = open("test.hex", "r") data = file.readlines() ``` 2. 解析每行数据 ``` for line in data: # 去除换行符 line = line.strip() # 解析行号、数据类型、地址和数据 line_no = int(line[1:3], 16) data_type = int(line[7:9], 16) addr = int(line[3:7], 16) line_data = line[9:-2] # 根据数据类型解析数据 if data_type == 0: # 数据记录 for i in range(0, len(line_data), 2): byte = int(line_data[i:i+2], 16) # 处理数据 elif data_type == 1: # 结束记录 break elif data_type == 2: # 扩展线性地址记录 addr_offset = int(line_data, 16) * 16 elif data_type == 3: # 扩展段地址记录 pass else: # 其他记录类型 pass ``` 3. 处理数据 根据数据类型解析出的数据,可以进行相应的处理。例如,如果是数据记录,可以将数据写入指定的内存地址;如果是扩展线性地址记录,可以计算出偏移地址。 完整的代码示例: ``` file = open("test.hex", "r") data = file.readlines() addr_offset = 0 for line in data: # 去除换行符 line = line.strip() # 解析行号、数据类型、地址和数据 line_no = int(line[1:3], 16) data_type = int(line[7:9], 16) addr = int(line[3:7], 16) + addr_offset line_data = line[9:-2] # 根据数据类型解析数据 if data_type == 0: # 数据记录 for i in range(0, len(line_data), 2): byte = int(line_data[i:i+2], 16) # 处理数据 print(hex(addr), hex(byte)) addr += 1 elif data_type == 1: # 结束记录 break elif data_type == 2: # 扩展线性地址记录 addr_offset = int(line_data, 16) * 16 elif data_type == 3: # 扩展段地址记录 pass else: # 其他记录类型 pass file.close() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值