您好,欢迎来到爱够旅游网。
搜索
您的当前位置:首页SOC Boot学习(一)——ELF文件

SOC Boot学习(一)——ELF文件

来源:爱够旅游网

01 ELF Header组成

  • elf header
  • programm header table
  • section header table
  • section

02 read elf

#include <iostream>
using namespace std;

using ELF_Addr = uint_t;
using ELF_Off = uint_t;
using ELF_Half = uint16_t;
using ELF_Word = uint32_t;
using ELF_Sword = int32_t;
using ELF_Xword = uint_t;
using ELF_Sxword = int_t;

/* 
e_ident[16]
包含了Maigc Number用于表明这是一个ELF文件,共16字节。	
0~3:前4字节为Magic Number,固定为、'\\0x7f' 'E' 'L' 'F'。
4(EI_CLASS):00为非法文件,01位32位,02为位。
5(EI_DATA):00为非法数据编码,01为小端序,02为大端序。
6(EI_VERSION):文件版本,固定为01。
7(EI_OSABI):操作系统ABI标识(实际未使用)。
8(EI_ABIVERSION):ABI版本(实际 未使用)。
9~15:对齐填充,无实际意义。
*/

typedef struct {
    unsigned char e_ident[16]; 

    ELF_Half e_type;  // 可重定位、可执行、共享目标文件
    ELF_Half e_machine; // CPU架构
    ELF_Word e_version;
    ELF_Addr e_entry;
    ELF_Off e_phoff;
    ELF_Off e_shoff;
    ELF_Word e_flags;
    ELF_Half e_ehsize;
    ELF_Half e_phentsize;
    ELF_Half e_phnum;
    ELF_Half e_shentsize;
    ELF_Half e_shnum;
    ELF_Half e_shstrndx;
} ELF_Ehdr;

typedef struct {
    ELF_Half p_type;
    ELF_Half p_flags;
    ELF_Off p_offset;
    ELF_Half p_offset;
    ELF_Addr p_vaddr;
    ELF_Addr p_paddr;
    ELF_Xword p_filesz;
    ELF_Xword p_memsz;
    ELF_Xword p_align;
} ELF_Phdr;

typedef struct {
    ELF_Word sh_name;
    ELF_Word sh_type;
    ELF_Xword sh_flags;
    ELF_Addr sh_addr;
    ELF_Off sh_offset;
    ELF_Xword sh_size;
    ELF_Word sh_link;
    ELF_Word sh_info;
    ELF_Xword sh_addralign;
    ELF_Xword sh_entsize;
} ELF_Shdr;

int main() {
    char filename[10010];

    cin >> filename;
    FILE *fp = fopen(filename, "r");

    if (fp == NULL) {
        cout << "fail to open file" << endl;
        exit(0);
    }

    ELF_Ehdr elf_head;
    int shnum, status;

    status = fread(&elf_head, sizeof(ELF_Ehdr), 1, fp);

    if (status == 0) {
        cout << "fail to read elf header" << endl;
        exit(0);
    }

    if (elf_head.e_ident[0] != 0x7f ||
        elf_head.e_ident[1] != 'E' ||
        elf_head.e_ident[2] != 'L' ||
        elf_head.e_ident[3] != 'F') {
        
        cout << "not a elf file" << endl;
        exit(0);
    }

    printf("程序入口(start标签位置) %#x\\n\\n",elf_head.e_entry);
 
    printf("Program header table文件中偏移 %#x\\n",elf_head.e_phoff);
    printf("Program header table大小 %#x\\n",elf_head.e_phentsize*elf_head.e_phnum);
    printf("Program header数量 %d\\n\\n",elf_head.e_phnum);
 
    printf("Section header table文件中偏移 %#x\\n",elf_head.e_shoff);
    printf("Section header table大小 %#x\\n",elf_head.e_shentsize*elf_head.e_shnum);
    printf("Section header数量 %d\\n\\n",elf_head.e_shnum);
 
    // 解析Segment Header
 
    // 制作Segment Header数组用来存储每一个Segment Header
    ELF_Phdr *phdr = (ELF_Phdr*)malloc(sizeof(ELF_Phdr) * elf_head.e_phnum);
	if (NULL == phdr)
	{
		printf("phdr malloc failed\\n");
		exit(0);
	}
 
    // 设置文件偏移量,定位到e_phoff
	status = fseek(fp, elf_head.e_phoff, SEEK_SET);
	if (0 != status)
	{
		printf("\\nfaile to fseek\\n");
		exit(0);
	}
 
	// 读取所有Segment Header 到 phdr, 大小为sizeof(Elf_Phdr) * 数量
	status = fread(phdr, sizeof(ELF_Phdr) * elf_head.e_phnum, 1, fp);
	if (0 == status)
	{
		printf("\\nfail to read segment\\n");
		exit(0);
	}
 
    // 重置指针位置到文件流开头
	rewind(fp);
 
    // 遍历每一个Segment Header
	for (int i = 0; i < elf_head.e_phnum; i++)
	{
		printf("段首的偏移: %#x\\n", phdr[i].p_offset);
		printf("段在文件中的大小: %#x\\n", phdr[i].p_filesz);
        printf("段的运行时虚拟内存地址: %#x\\n", phdr[i].p_vaddr);
        printf("段在内存中的大小: %#x\\n", phdr[i].p_memsz);
        printf("\\n");
	}
 
	
    // 解析Section Header
	// 制作Section Header数组用来存储每一个Section Header
	ELF_Shdr *shdr = (ELF_Shdr*)malloc(sizeof(ELF_Shdr) * elf_head.e_shnum);
	if (NULL == shdr)
	{
		printf("shdr malloc failed\\n");
		exit(0);
	}
 
	// 设置文件偏移量,定位到e_shoff
	status = fseek(fp, elf_head.e_shoff, SEEK_SET);
	if (0 != status)
	{
		printf("\\nfaile to fseek\\n");
		exit(0);
	}
 
	// 读取所有Segment Header 到 phdr, 大小为sizeof(Elf_Phdr) * 数量
	status = fread(shdr, sizeof(ELF_Shdr) * elf_head.e_shnum, 1, fp);
	if (0 == status)
	{
		printf("\\nfail to read section\\n");
		exit(0);
	}
 
	// 重置指针位置到文件流开头
	rewind(fp);
 
	// 读取每个Section的名字
	// 将fp指针移到字符串表(.shstrtab)内容的偏移位置处
	fseek(fp, shdr[elf_head.e_shstrndx].sh_offset, SEEK_SET);
 
	// e_shstrndx项是字符串表(.shstrtab)的下标
	// 把这个段的内容全部存储到shstrtab数组里面
    uint_t size = shdr[elf_head.e_shstrndx].sh_size; 
	char *shstrtab = (char*) malloc(size);
	char *temp = shstrtab;
 
	// 读取内容
	status = fread(shstrtab, shdr[elf_head.e_shstrndx].sh_size, 1, fp);
	if (0 == status)
	{
		printf("\\nfaile to read\\n");
	}
    
	// 遍历每一个节
	for (int i = 0; i < elf_head.e_shnum; i++)
	{
		// temp指针用于定位当前节的名字在.shstrtab节内容中的首地址
		temp = shstrtab;
		// shdr[i].sh_name表示这个节名字在(.shstrtab)节内容中的偏移
		temp = temp + shdr[i].sh_name;
		printf("节的名称: %s\\n", temp);
		printf("节首的偏移: %#x\\n", shdr[i].sh_offset);
		printf("节的大小: %#x\\n", shdr[i].sh_size);
        printf("节的运行时虚拟内存地址: %#x\\n", shdr[i].sh_addr);
        printf("\\n");
	}
    system("pause");
    return 0;
}

因篇幅问题不能全部显示,请点此查看更多更全内容

Copyright © 2019- igbc.cn 版权所有 湘ICP备2023023988号-5

违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com

本站由北京市万商天勤律师事务所王兴未律师提供法律服务