ELF文件解析和加载(附代码)

目录:

1.    elf文件基本概念
2.    elf文件结构

3.    elf文件装载

4.    代码实现

1.elf文件基本概念

elf文件是一种目标文件格式,用于定义不同类型目标文件以什么样的格式,都放了些什么东西。主要   用于linux平台。windows下是PE/COFF格式。       

    可执行文件、可重定位文件(.o)、共享目标文件(.so)、核心转储文件都是以elf文件格式存储的。

ELF文件组成部分:文件头、段表(section)、程序头

2.elf文件结构 ---- 文件头

文件头数据结:


ccs中解析出来的文件头信息


从上图中可以看到,elf文件头定义了文件的整体属性信息,比较重要的几个属性是:魔术字,入口地址,程序头位置、长度和数量,文件头大小(52字节),段表位置、长度和 个数。

2.elf文件结构---段表

段表(section)数据结构



解析段表内容


几个重要的段:.text(代码)段 、.data(数据)段、.bss段 。

.text:保存程序代码,权限为只读

.data:保存已初始化的全局变量和局部静态变量,可读可写

.bss:保存未初始化的全局变量和局部静态变量。初始化为0的变量也会保存在.bss段。可读可写。

2.elf文件结构 ---- 程序头

在ELF中把权限相同、又连在一起的段(section)叫做segment,操作系统正是按照“segment”来映射可执行文件的。

描述这些“segment”的结构叫做程序头,它描述了elf文件该如何被操作系统映射到内存空间中。

程序头数据结构


解析的程序头内容


由上图的程序头可知,该elf文件有9个LOAD类型的segment,因为只有LOAD类型是需要被映射的。

我们需要做的是找到这些segment在文件中的位置,并将其加载到对应的内存空间,对于memsiz大于filesiz的部分全部填充为0,加载完之后让程序跳转到入口地址

3.elf文件装载

代码实现


   
   
  1. #include <stdio.h>
  2. /**
  3. * hello.c
  4. */
  5. #include <stdlib.h>
  6. #include <string.h>
  7. #include <elf32.h>
  8. #include <file.h>
  9. #include <errno.h>
  10. //#include <unistd.h>
  11. #define ELF_HEAD_LENGTH 128
  12. #define MAGIC_NUM 0x464c457f
  13. #define SECTION_TABLE_MAX 40
  14. static uint32_t SecTableStrIndx = 0;
  15. uint32_t SecStrTableOff = 0;
  16. uint16_t SecTabNum = 0;
  17. /**elf 文件头和section表解析和检查***/
  18. int check_elf_head(FILE *file )
  19. {
  20. FILE *file_elf = file;
  21. int i = 0;
  22. int MagNum = 0;
  23. unsigned long file_size = 0;
  24. int sechnum = 0;
  25. uint32_t symsize = 0;
  26. uint32_t symoff = 0;
  27. uint32_t nSyms = 0,kk= 0;
  28. struct Elf32_Ehdr *Elf_header = NULL;
  29. struct Elf32_Shdr *Section_header = NULL;
  30. struct Elf32_Sym *Symbol_tab = NULL;
  31. //file_elf = fopen(path,"r");
  32. /*文件大小*/
  33. fseek(file_elf, 0,SEEK_END);
  34. file_size = ftell(file_elf);
  35. fseek(file_elf, 0,SEEK_SET);
  36. printf( "file total size is:%ld bytes\n",file_size);
  37. fread(Elf_header,sizeof(struct Elf32_Ehdr), 1,file_elf);
  38. printf( "\nSection Name String Table index: %d\n",SecTableStrIndx);
  39. /**ELF header解析**/
  40. printf( "Magic:\t");
  41. for(MagNum= 0; MagNum< 16; MagNum++)
  42. {
  43. printf( "%02x ",Elf_header->e_ident[MagNum]);
  44. }
  45. /**确认是否为elf格式**/
  46. if((Elf_header->e_ident[ 0] == '\x7f') && (Elf_header->e_ident[ 1] == ELFMAG1) \
  47. && (Elf_header->e_ident[ 2] == ELFMAG2) && (Elf_header->e_ident[ 3] == ELFMAG3))
  48. {
  49. printf( "\nThis is ELF file!\n");
  50. }
  51. else
  52. {
  53. printf( "\n NOT ELF file!\n");
  54. return -1;
  55. }
  56. printf( "\n");
  57. printf( "Type: \t%d\n",Elf_header->e_type);
  58. printf( "Machine: \t%d\n",Elf_header->e_machine); /* Architecture */
  59. printf( "Version: \t%#02x\n",Elf_header->e_version);
  60. printf( "Entry point address: \t%#02x\n",Elf_header->e_entry);
  61. printf( "Start of program headers: \t%d(bytes)\n",Elf_header->e_phoff);
  62. printf( "Start of section headers: \t%d(bytes)\n",Elf_header->e_shoff);
  63. printf( "Flags: \t%#02x\n",Elf_header->e_flags);
  64. printf( "Size of this header: \t%d(bytes)\n",Elf_header->e_ehsize);
  65. printf( "Size of program headers: \t%d(bytes)\n",Elf_header->e_phentsize);
  66. printf( "Number of program headers: \t%d\n",Elf_header->e_phnum);
  67. printf( "Size of section headers: \t%d(bytes)\n",Elf_header->e_shentsize);
  68. printf( "Number of section headers: \t%d\n",Elf_header->e_shnum);
  69. printf( "Section header string table index:\t%d\n",Elf_header->e_shstrndx);
  70. if(Elf_header->e_ehsize != sizeof(*Elf_header))
  71. {
  72. printf( "\nELF file header size is err\n!");
  73. return -1;
  74. }
  75. if(Elf_header->e_type != ET_REL && Elf_header->e_type != ET_EXEC )
  76. {
  77. printf( "file type is err!__FUNCTION__ %s __LINE__ %d\n", __FUNCTION__, __LINE__);
  78. }
  79. /**section header**/
  80. sechnum = Elf_header->e_shnum;
  81. fseek(file_elf,Elf_header->e_shoff,SEEK_SET);
  82. printf( "\n/*****section header table****/\n");
  83. fread(Section_header,sizeof(struct Elf32_Shdr),sechnum,file_elf);
  84. printf( "[Nr] Name Type Addr Off Size ES Flg Al");
  85. for(i= 0; i<sechnum; i++)
  86. {
  87. printf( "\n[%d] %x %2x %08x %06x %06x %02x %02x %02x "\
  88. , i,Section_header->sh_name,Section_header->sh_type,Section_header->sh_addr,\
  89. Section_header->sh_offset,Section_header->sh_size,Section_header->sh_entsize,\
  90. Section_header->sh_flags,Section_header->sh_addralign);
  91. if(Section_header->sh_type == 2) /*if symtab*/
  92. {
  93. symsize = Section_header->sh_size;
  94. symoff = Section_header->sh_offset;
  95. nSyms = symsize/(Section_header->sh_entsize);
  96. fseek(file_elf,symoff,SEEK_SET);
  97. fread(Symbol_tab,sizeof(struct Elf32_Sym),nSyms ,file_elf);
  98. }
  99. Section_header++;
  100. }
  101. printf( "\n\n*******symbol table******");
  102. printf( "\nid size other bind\n");
  103. /*while(kk < nSyms)
  104. {
  105. if(Symbol_tab->st_shndx == 2) //ext
  106. {
  107. printf("[%d] %x %x %x\n",kk,Symbol_tab->st_size,\
  108. Symbol_tab->st_other,(Symbol_tab->st_info)>>4 );
  109. }
  110. kk++;
  111. Symbol_tab++;
  112. }*/
  113. return 0;
  114. }
  115. /*** Program Header Table ,只有可执行文件和共享文件有程序头,linux命令:readelf -l xx 可查看结构***/
  116. void ProgramHeadInfo(FILE *file,struct Elf32_Phdr *ProHead)
  117. {
  118. FILE *file_elf = file;
  119. struct Elf32_Ehdr *Elf_header = NULL;
  120. struct Elf32_Phdr *Pro_header = NULL;
  121. uint32_t phoffset = 0; //程序头表偏移
  122. uint16_t phnum = 0; //程序头表数目
  123. uint16_t phentsize = 0; // 程序头表大小
  124. int num = 0;
  125. Elf_header = (struct Elf32_Ehdr *)malloc(sizeof(struct Elf32_Ehdr));
  126. memset(Elf_header, 0,sizeof(struct Elf32_Ehdr));
  127. fseek(file_elf, 0,SEEK_SET);
  128. fread(Elf_header,sizeof(struct Elf32_Ehdr), 1,file_elf);
  129. phoffset = Elf_header->e_phoff;
  130. phnum = Elf_header->e_phnum;
  131. phentsize = Elf_header->e_phentsize;
  132. fseek(file_elf,phoffset,SEEK_SET);
  133. //fread((struct Elf32_Phdr*)Pro_header,phentsize,phnum,file_elf);
  134. fread((struct Elf32_Phdr *)Pro_header,phentsize,phnum,file_elf);
  135. //ProHead = Pro_header;
  136. memcpy((char *)ProHead, (char *)Pro_header, sizeof(struct Elf32_Ehdr));
  137. printf( "\n/*****Program Headers:*****/\n");
  138. printf( "starting at offset: %d\n",phoffset);
  139. printf( "Number of program headers: %d\n",phnum);
  140. printf( "Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg\n");
  141. for(num= 0; num<phnum; num++)
  142. {
  143. printf( "%d %-#6x %-#x %-#x %-#5x %-#5x %-#x\n",Pro_header->p_type,Pro_header->p_offset,\
  144. Pro_header->p_vaddr,Pro_header->p_paddr\
  145. ,Pro_header->p_filesz,Pro_header->p_memsz,Pro_header->p_flags);
  146. Pro_header++;
  147. }
  148. free(Elf_header);
  149. Elf_header = NULL;
  150. return;
  151. }
  152. /**加载elf文件segment 到内存中
  153. 返回值: elf的entry point**/
  154. typedef void (*pCALLFUNC)(void);
  155. uint32_t LoadElf2Mem(FILE *file )
  156. {
  157. struct Elf32_Phdr *ProHead = NULL;
  158. struct Elf32_Ehdr *Elf_header = NULL;
  159. FILE *file1 = file;
  160. uint16_t i = 0;
  161. int size= 0;
  162. uint32_t addrPoint = 0;
  163. Elf_header = (struct Elf32_Ehdr *)malloc(sizeof(struct Elf32_Ehdr));
  164. memset(Elf_header, 0,sizeof(struct Elf32_Ehdr));
  165. fseek(file1, 0,SEEK_SET);
  166. size = fread(Elf_header, sizeof(struct Elf32_Ehdr), 1, file1);
  167. ProgramHeadInfo(file1,ProHead);
  168. for(i= 0;i< Elf_header->e_phnum; i++,ProHead++)
  169. {
  170. if(ProHead->p_type != PT_LOAD )
  171. {
  172. printf( "\nnot PT_LOAD %d %d size: %d\n", Elf_header->e_phnum,ProHead->p_type,size);
  173. continue;
  174. }
  175. if(ProHead->p_filesz)
  176. {
  177. fseek( file1,ProHead->p_offset,SEEK_SET);
  178. if((size = fread((char *)ProHead->p_vaddr, 1,ProHead->p_filesz,file1)) != ProHead->p_filesz)
  179. {
  180. printf( "\nfunction:%s,line:%d, read p_vaddr err!\n", __FUNCTION__, __LINE__);
  181. printf( "\nread 返回值%d\n",size);
  182. printf( "read(file,ProHead->p_vaddr,ProHead->p_filesz) != ProHead->p_filesz %x p_filesz %d\n",\
  183. ProHead->p_vaddr,ProHead->p_filesz);
  184. //return;
  185. }
  186. }
  187. /**多余的空间写0,做BSS段**/
  188. if((ProHead->p_filesz) < (ProHead->p_memsz))
  189. {
  190. memset((char*)ProHead->p_vaddr+ProHead->p_filesz,
  191. 0,
  192. ProHead->p_memsz - ProHead->p_filesz);
  193. }
  194. else{}
  195. }
  196. //pEntry = (uint32_t *)Elf_header->e_entry;
  197. addrPoint = Elf_header->e_entry;
  198. printf( "\nEntry point address:%x",addrPoint);
  199. free(Elf_header);
  200. Elf_header = NULL;
  201. return addrPoint;
  202. }
  203. int main(void)
  204. {
  205. char *path = "D:/workspace_v7/test_one/Debug/app.out";
  206. FILE *file_elf = NULL;
  207. file_elf = fopen(path, "rb");
  208. pCALLFUNC pEntry = (pCALLFUNC) NULL;
  209. uint32_t addr = 0;
  210. if(file_elf == NULL)
  211. {
  212. printf( "open file err!!%s\n",strerror(errno));
  213. return -1;
  214. }
  215. check_elf_head(file_elf);
  216. addr = LoadElf2Mem(file_elf);
  217. pEntry = (pCALLFUNC)addr;
  218. fclose(file_elf);
  219. pEntry();
  220. }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值