QT程序C++axf转hexelf转hex·

基于QT5.axf,elf转.hex的C++实现

Hugh

Hugh

59 0

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;
}

相关文章

优先推荐同专题、同标签和同作者内容,补足热门文章。

评论 0

登录 后参与评论

评论

成为第一个评论的人