失眠网,内容丰富有趣,生活中的好帮手!
失眠网 > C语言解析FLM(ELF)格式文件

C语言解析FLM(ELF)格式文件

时间:2024-06-03 02:07:48

相关推荐

C语言解析FLM(ELF)格式文件

C语言解析FLM(ELF)格式文件

本章博客涉及到的软件及代码,关注以下公众号,回复关键字flmparse获取下载链接!

1、前言

写这篇博客的目的是因为最近在做一个STM32的离线编程器,离线下载需要用到FLM文件的下载算法,所以实现了一下提取FLM文件中下载算法的C程序。

有关ELF格式的详细说明可查看这个文件:http://flint.cs.yale.edu/cs422/doc/ELF_Format.pdf

推荐一个elf分析软件:/index.html,软件如下图:

2、快速扫盲

ELF 全称 “Executable and Linkable Format”,即可执行可链接文件格式,目前常见的Linux、 Android可执行文件、共享库(.so)、目标文件( .o)以及Core 文件(吐核)均为此格式。

常见的ELF文件大致结构如下:

如果是LINUX系统,使用GCC编译出来的程序就是该格式,性质等同于windows系统下的.exe格式运行程序;在keil中,编译完成之后有一个.axf文件,这个文件也是elf格式;FLM格式文件是KEIL里的FLASH下载算法文件,他其实就是.axf文件的拷贝,换了个后缀名称而已。

3、运行效果

我提供了两种可执行程序,一是带UI界面的,一个是控制台使用的,效果如下所示:

控制台应用程序:

可执行应用程序:

4、源码实现

由于elf.h这个头文件太大了,就不在博客里贴代码了,只贴一下flm文件的解析:

/** flmparse.c** Created on: 4月10日*Author: hello*/#include <stdio.h>#include <stdint.h>#include <fcntl.h>#include <unistd.h>#include <ctype.h>#include "elf.h"#define FILENAME "STM32F4xx_2048.FLM"static int ReadDataFromFile(const char* FName, uint32_t offset, void* buf, uint32_t size);static int FLM_Prase(const void* FName, void* pBuffer, uint32_t* Size, uint32_t* Init, uint32_t* UnInit, uint32_t* EraseChip, uint32_t* EraseSector, uint32_t* ProgramPage);int main(int argc, char const *argv[]){int i = 0;uint32_t RAM[256] = {0};uint32_t Addr[5] = {0};uint32_t Size = 0;if(argc != 2){printf("\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n");printf("Usage:\n");printf(" flmparse.exe [filename]\n");printf("\n\n");goto __exit;}/* 这8个数是中断halt程序,让函数执行完后返回到这里来执行从而让CPU自动halt住 */RAM[0] = 0xE00ABE00;RAM[1] = 0x062D780D;RAM[2] = 0x24084068;RAM[3] = 0xD3000040;RAM[4] = 0x1E644058;RAM[5] = 0x1C49D1FA;RAM[6] = 0x2A001E52;RAM[7] = 0x4770D1F2;if(FLM_Prase(argv[1], &RAM[8], &Size, &Addr[0],&Addr[1],&Addr[2],&Addr[3],&Addr[4]) < 0){printf("错误:解析FLM格式文件失败,请检查FLM文件是否存在或格式正确性!\r\n");goto __exit;}fprintf(stdout, "\r\n>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\r\n");Size += 32;fprintf(stdout, "\r\nstatic const uint32_t flash_code[] = \n{");for(i = 0; i < (Size >> 2); i++){if(i % 8 == 0){fprintf(stdout, "\n ");}fprintf(stdout, "0X%08X,", RAM[i]);}fprintf(stdout, "\n};\n");fprintf(stdout, "\r\nconst program_target_t flash_algo =\n{\n");fprintf(stdout, " 0X%08X, // Init\n", Addr[0] + 0X20000020);fprintf(stdout, " 0X%08X, // UnInit\n",Addr[1] + 0X20000020);fprintf(stdout, " 0X%08X, // EraseChip\n", Addr[2] + 0X20000020);fprintf(stdout, " 0X%08X, // EraseSector\n", Addr[3] + 0X20000020);fprintf(stdout, " 0X%08X, // ProgramPage\n", Addr[4] + 0X20000020);fprintf(stdout, "\n");fprintf(stdout, " // BKPT : start of blob + 1\n");fprintf(stdout, " // RSB : address to access global/static data\n");fprintf(stdout, " // RSP : stack pointer\n");fprintf(stdout, " {\n");fprintf(stdout, " 0X20000001,\n");fprintf(stdout, " 0X20000C00,\n");fprintf(stdout, " 0X20001000,\n");fprintf(stdout, " },\n");fprintf(stdout, "\n");fprintf(stdout, " 0x20000400, // mem buffer location\n");fprintf(stdout, " 0x20000000, // location to write prog_blob in target RAM\n");fprintf(stdout, " sizeof(flash_code), // prog_blob size\n");fprintf(stdout, " flash_code, // address of prog_blob\n");fprintf(stdout, " 0x00000400, // ram_to_flash_bytes_to_be_written\n");fprintf(stdout, "};\n");fprintf(stdout, "\n");fprintf(stdout, "\n");fprintf(stdout, "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n");__exit:return 0;}static int ReadDataFromFile(const char* FName, uint32_t offset, void* buf, uint32_t size){int ret = 0;int fd = 0;if ((fd = open(FName, O_RDONLY | O_BINARY)) < 0){ret = -1;goto __exit;}if (lseek(fd, offset, SEEK_SET) < 0){ret = -2;goto __exit;}if (read(fd, buf, size) != size){ret = -3;goto __exit;}__exit: close(fd);return ret;}int FLM_Prase(const void* FName, void* pBuffer, uint32_t* Size, uint32_t* Init, uint32_t* UnInit, uint32_t* EraseChip, uint32_t* EraseSector, uint32_t* ProgramPage){#define LOAD_FUN_NUM 5uint8_t buffer[1024] = {0};int i = 0, k = 0;int found = 0;const Elf32_Phdr* pPhdr = (const Elf32_Phdr *) buffer;const Elf32_Shdr* pShdr = (const Elf32_Shdr *) buffer;const Elf32_Sym* pSymbol = (const Elf32_Sym *) buffer;Elf32_Ehdr ehdr = {0};// ELF文件信息头Elf32_Shdr ShdrSym = {0}; // 符号表头Elf32_Shdr ShdrStr = {0}; // 字符串表头const char* StrFunNameTable[LOAD_FUN_NUM] = {"Init", "UnInit", "EraseChip", "EraseSector", "ProgramPage"};int StrFunIndexTable[LOAD_FUN_NUM] = {-1, -1, -1, -1, -1};//// 读取ELF文件头信息(ELF Header)//ReadDataFromFile(FName, 0, &ehdr, sizeof(Elf32_Ehdr));// 不是ELF格式文件if (strstr((const char *)ehdr.e_ident, "ELF") == NULL){return -1;}//// 读取程序头信息(Program Header)//ReadDataFromFile(FName, ehdr.e_phoff, buffer, sizeof(Elf32_Phdr) * ehdr.e_phnum);for (i = 0; i < ehdr.e_phnum; i++){if (pPhdr[i].p_type == PT_LOAD && (pPhdr[i].p_flags & (PF_X | PF_W | PF_R)) == (PF_X | PF_W | PF_R)){if (pPhdr[i].p_filesz > sizeof(buffer)) // RAM代码过大{return -2;}if(ReadDataFromFile(FName, pPhdr[i].p_offset, pBuffer, pPhdr[i].p_filesz) < 0) // 提取需要下载到RAM的程序代码{return -3;}printf("====:%d\r\n", pPhdr[i].p_filesz);*Size = pPhdr[i].p_filesz;}}//// 读取节区头部(Sections Header)//ReadDataFromFile(FName, ehdr.e_shoff, buffer, sizeof(Elf32_Shdr) * ehdr.e_shnum);// 查找符号表头并拷贝出来备用for (i = 0; i < ehdr.e_shnum; i++){if (pShdr[i].sh_type == SHT_SYMTAB){memcpy(&ShdrSym, &pShdr[i], sizeof(Elf32_Shdr));// 查找字符串表头并拷贝出来备用if (pShdr[ShdrSym.sh_link].sh_type == SHT_STRTAB){memcpy(&ShdrStr, &pShdr[ShdrSym.sh_link], sizeof(Elf32_Shdr));found = 1;break;}}}if(!found){return -4;}//// 根据字符串表头读取所有字符串表//ReadDataFromFile(FName, ShdrStr.sh_offset, buffer, ShdrStr.sh_size);for (i = 0; i < ShdrStr.sh_size; i++) if (buffer[i] == '\0') buffer[i] = '\n';buffer[ShdrStr.sh_size] = 0;for (i = 0; i < LOAD_FUN_NUM; i++){char* p = NULL;if (StrFunNameTable[i] != NULL && (p = strstr((const char *) buffer, StrFunNameTable[i])) != NULL){StrFunIndexTable[i] = (uint32_t) p - (uint32_t) buffer;}}//// 读取符号表//ReadDataFromFile(FName, ShdrSym.sh_offset, buffer, ShdrSym.sh_size);// 遍历查询我们用到的函数符号for (i = 0; i < ShdrSym.sh_size / sizeof(Elf32_Sym); i++, pSymbol++){for (k = 0; k < LOAD_FUN_NUM; k++){if (StrFunIndexTable[k] >= 0 && StrFunIndexTable[k] == pSymbol->st_name) // symbol.st_name的值就是偏移地址{switch (k){case 0:*Init = pSymbol->st_value;break;case 1:*UnInit = pSymbol->st_value;break;case 2:*EraseChip = pSymbol->st_value;break;case 3:*EraseSector = pSymbol->st_value;break;case 4:*ProgramPage = pSymbol->st_value;break;default:break;}}}}return 0;}

ends…

如果觉得《C语言解析FLM(ELF)格式文件》对你有帮助,请点赞、收藏,并留下你的观点哦!

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。