1.头文件axf2hex.h
// axf2hex.h
#ifndef AXF2HEX_H
#define AXF2HEX_H
#include <QString>
/**
* @brief 将.axf文件转换为.hex格式
* @param axfFilePath 输入.axf文件路径
* @param hexFilePath 输出.hex文件路径
* @return 是否成功
*/
bool ry_axf2hex(const QString& axfFilePath, const QString& hexFilePath);
#endif // AXF2HEX_H
2.源文件 axf2hex.cpp
// axf2hex.cpp
#include "axf2hex.h"
#include <QFile>
#include <QTextStream>
#include <QDebug>
#include <QPair>
#include <cstdint>
// ELF32头部结构
struct Elf32_Ehdr {
unsigned char e_ident[16]; // ELF标识
uint16_t e_type; // 对象文件类型
uint16_t e_machine; // 运行平台
uint32_t e_version; // ELF版本号
uint32_t e_entry; // 入口地址
uint32_t e_phoff; // 程序头表偏移
uint32_t e_shoff; // 节头表偏移
uint32_t e_flags; // 处理器标志
uint16_t e_ehsize; // ELF头大小
uint16_t e_phentsize; // 程序头表项大小
uint16_t e_phnum; // 程序头表项数量
uint16_t e_shentsize; // 节头表项大小
uint16_t e_shnum; // 节头表项数量
uint16_t e_shstrndx; // 节名字符串表索引
};
// ELF32程序头结构
struct Elf32_Phdr {
uint32_t p_type; // 段类型
uint32_t p_offset; // 段在文件中的偏移
uint32_t p_vaddr; // 虚拟地址
uint32_t p_paddr; // 物理地址
uint32_t p_filesz; // 段在文件中所占大小
uint32_t p_memsz; // 段在内存中所占大小
uint32_t p_flags; // 标志
uint32_t p_align; // 内存对齐
};
enum : uint32_t {
PT_LOAD = 1 // 可加载段
};
// 计算校验和(修正版)
// 正确算法:所有字节之和的补码(低8位)
static uint8_t calculateChecksum(uint8_t length, uint16_t address, uint8_t type, const QByteArray& data)
{
uint8_t sum = 0;
// 累加长度字节
sum += length;
// 累加地址的两个字节
sum += (address >> 8) & 0xFF; // 高8位
sum += address & 0xFF; // 低8位
// 累加类型字节
sum += type;
// 累加数据字节
for (int i = 0; i < data.size(); ++i) {
sum += static_cast<uint8_t>(data.at(i));
}
// 取补码(256 - 总和的低8位)
return static_cast<uint8_t>(0x100 - (sum & 0xFF));
}
// 写入一行HEX数据
static void writeHexLine(QTextStream& out, uint32_t address, uint8_t type, const QByteArray& data)
{
// 计算校验和(使用修正后的算法)
uint8_t checksum = calculateChecksum(
static_cast<uint8_t>(data.size()),
static_cast<uint16_t>(address & 0xFFFF), // 地址只取低16位
type,
data
);
// 构建HEX行
QByteArray line;
line.append(':');
line.append(QString("%1").arg(data.size(), 2, 16, QChar('0')).toUpper());
line.append(QString("%1").arg(address, 4, 16, QChar('0')).toUpper());
line.append(QString("%1").arg(type, 2, 16, QChar('0')).toUpper());
for (int i = 0; i < data.size(); ++i) {
line.append(QString("%1").arg(static_cast<uint8_t>(data.at(i)), 2, 16, QChar('0')).toUpper());
}
line.append(QString("%1").arg(checksum, 2, 16, QChar('0')).toUpper());
out << line << "\r\n";
}
// 写入扩展线性地址记录(类型04)
static void writeExtendedAddressRecord(QTextStream& out, uint16_t upper16)
{
QByteArray data;
data.append(static_cast<char>(upper16 >> 8)); // 高8位
data.append(static_cast<char>(upper16 & 0xFF));// 低8位
writeHexLine(out, 0x0000, 0x04, data);
}
bool ry_axf2hex(const QString& axfFilePath, const QString& hexFilePath)
{
QFile inFile(axfFilePath);
if (!inFile.open(QIODevice::ReadOnly)) {
qDebug() << "无法打开AXF/ELF文件:" << axfFilePath;
return false;
}
QFile outFile(hexFilePath);
if (!outFile.open(QIODevice::WriteOnly | QIODevice::Text)) {
qDebug() << "无法创建HEX文件:" << hexFilePath;
return false;
}
QTextStream out(&outFile);
// 读取ELF头部
Elf32_Ehdr ehdr;
if (inFile.read((char*)&ehdr, sizeof(ehdr)) != sizeof(ehdr)) {
qDebug() << "读取ELF头部失败";
return false;
}
// 检查ELF魔数
if (ehdr.e_ident[0] != 0x7F || ehdr.e_ident[1] != 'E' ||
ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F') {
qDebug() << "不是ELF格式文件";
return false;
}
// 定位程序头表
inFile.seek(ehdr.e_phoff);
// 存储所有可加载段
QList<QPair<uint32_t, QByteArray>> loadSegments;
for (int i = 0; i < ehdr.e_phnum; ++i) {
Elf32_Phdr phdr;
if (inFile.read((char*)&phdr, sizeof(phdr)) != sizeof(phdr)) {
qDebug() << "读取程序头失败";
return false;
}
if (phdr.p_type == PT_LOAD) {
inFile.seek(phdr.p_offset);
QByteArray segmentData = inFile.read(phdr.p_filesz);
loadSegments.append(qMakePair(phdr.p_paddr, segmentData));
}
}
// 确定初始高16位地址
uint16_t initialUpper16 = 0x0800;
if (!loadSegments.isEmpty()) {
uint32_t firstAddress = loadSegments.first().first;
initialUpper16 = static_cast<uint16_t>((firstAddress >> 16) & 0xFFFF);
}
// 在文件第一行写入扩展线性地址记录
writeExtendedAddressRecord(out, initialUpper16);
uint16_t currentUpper16 = initialUpper16;
// 写入所有可加载段数据
for (int j = 0; j < loadSegments.size(); ++j) {
const QPair<uint32_t, QByteArray>& segment = loadSegments.at(j);
uint32_t baseAddress = segment.first;
const QByteArray& segmentData = segment.second;
int offset = 0;
while (offset < segmentData.size()) {
int chunkSize = qMin(16, segmentData.size() - offset);
uint32_t currentAddress = baseAddress + offset;
uint16_t upper16 = static_cast<uint16_t>((currentAddress >> 16) & 0xFFFF);
uint16_t lower16 = static_cast<uint16_t>(currentAddress & 0xFFFF);
if (upper16 != currentUpper16) {
writeExtendedAddressRecord(out, upper16);
currentUpper16 = upper16;
}
QByteArray chunk = segmentData.mid(offset, chunkSize);
writeHexLine(out, lower16, 0x00, chunk);
offset += chunkSize;
}
}
// 写入文件结束记录
writeHexLine(out, 0x0000, 0x01, QByteArray());
outFile.close();
inFile.close();
qDebug() << "AXF转HEX成功:" << hexFilePath;
return true;
}