请选择 进入手机版 | 继续访问电脑版

硬汉嵌入式论坛

 找回密码
 立即注册
查看: 1963|回复: 9
收起左侧

[固件] KEIL的flash编程算法文件FLM文件格式解析

[复制链接]

504

主题

1211

帖子

2224

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2224
发表于 2019-12-28 18:22:58 | 显示全部楼层 |阅读模式
提示: 该帖被管理员或版主屏蔽
回复

使用道具 举报

7769

主题

4万

帖子

6万

积分

管理员

健康的身体,健康的心态

Rank: 9Rank: 9Rank: 9

积分
61613
QQ
发表于 2019-12-29 09:38:41 | 显示全部楼层
20191229093755.jpg

20191229093802.jpg
淘宝小店: https://armfly.taobao.com/
尊重,冷静,专注,努力,用心的做好每一件事情,Fighting!
回复

使用道具 举报

504

主题

1211

帖子

2224

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2224
 楼主| 发表于 2019-12-29 10:24:30 | 显示全部楼层
现在已经可以正确解析FLM文件了,一个函数搞定。

大致步骤:
1、读52字节头部确定Program Header 和 Sections  Header 在文件中的位置和个数。
2、读取程序头Program Header(比如2个),确定需要加载到RAM的文件偏移地址和大小。
3、读取全部的Sections  Header (比如16个),找到哪个Sections  Header对应符号表头 (sh_type == SHT_SYMTAB).
4.  根据符号表的link字段确定关联的字符串表头(sh_type == SHT_STRTAB)。(字符串表在一个ELF文件中可能存在多个,因此需要link字段确认)
5、根据字符串表头,读取字符串内容,搜索如下字符串(FlashDevice数组、Init、UnInit、EraseChip、EraseSector、ProgramPage ),保存它们在字符串内容段中偏移地址(也就是字符串索引)
6、搜索符号表内容(每个符号占用16字节,其中包括符号在字符串表的索引值、值和大小等信息),根据函数名字符串的索引值,确定函数对应哪一行,读出st_value,st_size字段即可。
    st_value表示定位地址,st_size表示大小。
回复

使用道具 举报

504

主题

1211

帖子

2224

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
2224
 楼主| 发表于 2019-12-29 10:28:37 | 显示全部楼层
elf_file.h 文件:
/*
*********************************************************************************************************
*
*    模块名称 : elf文件解析模块
*    文件名称 : elf_file.h
*    说    明 : 头文件
*
*********************************************************************************************************
*/

#ifndef __ELF_FILE_H_
#define __ELF_FILE_H_

#define ELF_TEST_FILE_1    "0:/H7-TOOL/Programmer/FLM/ST/STM32F0xx/STM32F0xx_16.FLM"
#define ELF_TEST_FILE_2    "0:/H7-TOOL/Programmer/FLM/ST/STM32F4xx/STM32F446_Quad_SPI.FLM"
#define ELF_TEST_FILE_3    "0:/H7-TOOL/Programmer/FLM/ST/STM32H7x/STM32H743_H7-TOOLS_QSPI.FLM"

#define FUNC_NUM    8       /* 全局符号个数(函数和一个常量数组) */
#define LOAD_NUM    4       /* 需要加载到RAM的段个数 */

enum
{
    IDX_FlashDevice = 0,
    IDX_Init,
    IDX_UnInit,
    IDX_BlankCheck,
    IDX_EraseChip,
    IDX_EraseSector,
    IDX_ProgramPage,
    IDX_Verify,
};

typedef struct
{
    uint32_t Valid;
    uint32_t Offset;
    uint32_t Size;
}
ELF_FUNC_T;

typedef struct
{
    uint32_t Valid;
    uint32_t Offset;
    uint32_t Addr;
    uint32_t Size;   
}
ELF_LOAD_T;

/* FLM文件分析结构 */
typedef struct
{   
    uint32_t FileOk;   

    ELF_LOAD_T Load[LOAD_NUM];

    ELF_FUNC_T Func[FUNC_NUM];        
}FLM_PARSE_T;   

extern FLM_PARSE_T g_tFLM;

uint8_t ELF_ParseFile(char *_path);

#endif


elf_file.c 文件:
/*
*********************************************************************************************************
*
*    模块名称 : elf文件解码模块
*    文件名称 : elf_file.c
*    版    本 : V1.0
*    说    明 : 用于解码KEIL中FLM算法文件,提取加载到CPU RAM的代码。
*               FLM文件中的字符串表和符号表长度不能超过4096。
*
*    修改记录 :
*        版本号  日期        作者     说明
*        V1.0    2019-12-29  armfly   正式发布
*
*    Copyright (C), 2019-2030, 安富莱电子 www.armfly.com
*
*********************************************************************************************************
*/
#include "bsp.h"
#include "file_lib.h"
#include "elf_file.h"
#include "elf.h"

const char *strFuncName[FUNC_NUM] = {"FlashDevice", "Init", "UnInit", "BlankCheck",
        "EraseChip", "EraseSector", "ProgramPage", "Verify"};

FLM_PARSE_T g_tFLM;

/* 测试代码
    ELF_ParseFile(ELF_TEST_FILE_1);
    ELF_ParseFile(ELF_TEST_FILE_2);
    ELF_ParseFile(ELF_TEST_FILE_3);
    while(1);
*/

/*
*********************************************************************************************************
*    函 数 名: ELF_ParseFile
*    功能说明: 解析elf文件.  使用了 FsReadBuf[4096]全部变量做缓冲区。解析结果放到全局变量g_tFLM
*    形    参: _path : 文件路径
*    返 回 值: 0 = ok, 其他值表示错误
*********************************************************************************************************
*/
uint8_t ELF_ParseFile(char *_path)
{
    uint32_t bytes;
    uint32_t i,j;
    char *p;
    uint32_t StrFoud[FUNC_NUM] = {0};   
    uint32_t StrIdx[FUNC_NUM] = {0};  
    Elf_Ehdr Ehdr;
    Elf_Phdr *pPhdr;
    Elf_Shdr *pShdr;
    Elf_Sym *pSym;

    Elf_Shdr ShdrSym;   /* 符号表头 */
    Elf_Shdr ShdrStr;   /* 字符串表头 */

    /* 解析结果先全部清零 */
    for (i = 0; i < LOAD_NUM; i++)
    {
        g_tFLM.Load.Valid = 0;
         g_tFLM.Load
.Offset = 0;
        g_tFLM.Load
.Addr = 0;        
        g_tFLM.Load
.Size = 0;
    }

    for (i = 0; i < FUNC_NUM; i++)
    {
        g_tFLM.Func
.Valid = 0;
        g_tFLM.Func
.Offset = 0;
        g_tFLM.Func
.Size = 0;
    }   

    /* 解析文件头部 ELF Header */
    bytes = ReadFileToMem(_path, 0, FsReadBuf, 52);
    if (bytes != 52)
    {
        goto err;   /* 读文件错误 */
    }
    memcpy((char *)&Ehdr, FsReadBuf, sizeof(Elf_Ehdr));
    if (IS_ELF(Ehdr) == 0)
    {
        goto err;   /* 不是ELF文件 */
    }

    if (Ehdr.e_type != ET_EXEC)
    {
        goto err;   /* 不是可执行的镜像文件 */
    }   

    /* 解析程序头部(Program Header) - 2段 */
    if (Ehdr.e_phnum > LOAD_NUM)
    {
        goto err;   /* Program Header 个数过大 */
    }
    bytes = ReadFileToMem(_path, Ehdr.e_phoff, FsReadBuf, Ehdr.e_phnum * 32);
    if (bytes != Ehdr.e_phnum * 32)
    {
        goto err;   /* 读文件错误 */
    }

    for (i = 0; i < Ehdr.e_phnum; i++)
    {
        pPhdr = (Elf_Phdr *)(FsReadBuf + i * 32);
        if (pPhdr->p_type == PT_LOAD)
        {
            g_tFLM.Load
.Valid = 1;
            g_tFLM.Load
.Offset = pPhdr->p_offset;
            g_tFLM.Load
.Addr = pPhdr->p_vaddr;
            g_tFLM.Load
.Size = pPhdr->p_filesz;
        }
    }

    /* 解析节区头部 (Sections Header) */
    if (Ehdr.e_shnum < 25)
    {
        uint8_t found = 0;

        bytes = ReadFileToMem(_path, Ehdr.e_shoff, FsReadBuf, 40 * Ehdr.e_shnum);

        /* 先查找符号表 */        
        for (i = 0; i < Ehdr.e_shnum; i++)
        {
            pShdr = (Elf_Shdr *)(FsReadBuf + 40 * i);
            if (pShdr->sh_type == SHT_SYMTAB)
            {               
                memcpy((char *)&ShdrSym, (char *)pShdr, sizeof(Elf_Shdr));
                found++;
            }
        }
        if (found == 0)
        {
            goto err;   /* 未找到符号表 */
        }

        /* 查找符号表对应的字符串表 (ELF文件中可能有多个字符串表)*/  
        if (ShdrSym.sh_link >= Ehdr.e_shnum)
        {
            goto err;   /* 未找到字符串表 */
        }

        pShdr = (Elf_Shdr *)(FsReadBuf + 40 * ShdrSym.sh_link);
        if (pShdr->sh_type == SHT_STRTAB)
        {               
            memcpy((char *)&ShdrStr, (char *)pShdr, sizeof(Elf_Shdr));
        }
        else
        {
            goto err;   /* 未找到字符串表 */
        }        
    }   
    else
    {
        goto err;   /* Sections个数过大 */;
    }   

    /* 字符串表 */
    if (ShdrStr.sh_size < sizeof(FsReadBuf))
    {
        bytes = ReadFileToMem(_path, ShdrStr.sh_offset, FsReadBuf, ShdrStr.sh_size);  
        if (bytes == ShdrStr.sh_size)
        {
            p = FsReadBuf;
            for (i = 0; i < bytes - 1; i++)
            {
                if (*p++ == 0)
                {
                    for (j = 0; j < 8; j++)
                    {
                        if (strcmp(p, strFuncName[j]) == 0)
                        {
                            StrFoud[j] = 1;
                            StrIdx[j] = i + 1;
                        }
                    }
                }
            }
        }
        else
        {
            goto err;   /* 读文件失败 */
        }
    }
    else
    {
        goto err;       /* 字符串表过大 */
    }

    /* 解析符号表 */
    if (ShdrSym.sh_size < sizeof(FsReadBuf))
    {
        bytes = ReadFileToMem(_path, ShdrSym.sh_offset, FsReadBuf, ShdrSym.sh_size);  

        for (i = 0; i < bytes / sizeof(Elf_Sym); i++)
        {
            for (j = 0; j < FUNC_NUM; j++)
            {
                pSym = (Elf_Sym *)(FsReadBuf + 16 * i);
                if (pSym->st_name == StrIdx[j] && StrFoud[j] == 1)
                {
                    g_tFLM.Func[j].Valid = 1;
                    g_tFLM.Func[j].Offset = pSym->st_value;
                    g_tFLM.Func[j].Size = pSym->st_size;
                }
            }
        }
    }
    else
    {
        /* 符号表过大 */
    }

    return 0;   /* 解析成功 */

err:  
    return 1;   /* 解析失败 */   
}


回复

使用道具 举报

7769

主题

4万

帖子

6万

积分

管理员

健康的身体,健康的心态

Rank: 9Rank: 9Rank: 9

积分
61613
QQ
发表于 2019-12-29 11:26:50 | 显示全部楼层
armfly 发表于 2019-12-29 10:24
现在已经可以正确解析FLM文件了,一个函数搞定。

大致步骤:

太给力了。
淘宝小店: https://armfly.taobao.com/
尊重,冷静,专注,努力,用心的做好每一件事情,Fighting!
回复

使用道具 举报

0

主题

9

帖子

9

积分

新手上路

积分
9
发表于 2019-12-29 12:19:15 | 显示全部楼层
厉害了,日常崔更
回复

使用道具 举报

1

主题

7

帖子

9

积分

新手上路

积分
9
发表于 2020-2-28 15:33:35 | 显示全部楼层
硬件,怎么提示被屏蔽了?
回复

使用道具 举报

7769

主题

4万

帖子

6万

积分

管理员

健康的身体,健康的心态

Rank: 9Rank: 9Rank: 9

积分
61613
QQ
发表于 2020-2-28 15:37:26 | 显示全部楼层
longdelu 发表于 2020-2-28 15:33
硬件,怎么提示被屏蔽了?

楼主位的内容有误,看开源出来的源码就行。
淘宝小店: https://armfly.taobao.com/
尊重,冷静,专注,努力,用心的做好每一件事情,Fighting!
回复

使用道具 举报

0

主题

34

帖子

34

积分

新手上路

积分
34
发表于 2020-3-19 23:11:54 | 显示全部楼层

这个软件是什么?版主能告知下不
093802ithks3e2t3h0uzk2.jpg


回复

使用道具 举报

7769

主题

4万

帖子

6万

积分

管理员

健康的身体,健康的心态

Rank: 9Rank: 9Rank: 9

积分
61613
QQ
发表于 2020-3-20 09:22:32 | 显示全部楼层
icprg 发表于 2020-3-19 23:11
这个软件是什么?版主能告知下不

elf文件解析小软件elfparser
http://www.armbbs.cn/forum.php?m ... 6123&fromuid=58
(出处: 硬汉嵌入式论坛)
淘宝小店: https://armfly.taobao.com/
尊重,冷静,专注,努力,用心的做好每一件事情,Fighting!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2020-8-13 04:53 , Processed in 0.421201 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表