最近项目需要,要做一个小工具用来读取一堆库文件的版本信息,研究了下ELF文件。
实现思路:读取一个库文件,查找库的所有对外接口,如果接口名中带有Version字段,就通过dlsym系列函数读取版本信息。
以下只是学习ELF文件格式的记录。
在linux系统头文件elf.h能找到ELF文件格式相关定义,ELF的组成部分包括:
1、ELF头 (ELF Header)
2、程序段头(Program Header)
3、程序段(Program segment)
4、节区头(section Header)
5、节区(section)
当然不是每个ELF文件都完整的包括以上内容
1、ELF头
/* The ELF file header. This appears at the start of every ELF file. */
#define EI_NIDENT (16)
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf32_Half e_type; /* Object file type */
Elf32_Half e_machine; /* Architecture */
Elf32_Word e_version; /* Object file version */
Elf32_Addr e_entry; /* Entry point virtual address */
Elf32_Off e_phoff; /* Program header table file offset */
Elf32_Off e_shoff; /* Section header table file offset */
Elf32_Word e_flags; /* Processor-specific flags */
Elf32_Half e_ehsize; /* ELF header size in bytes */
Elf32_Half e_phentsize; /* Program header table entry size */
Elf32_Half e_phnum; /* Program header table entry count */
Elf32_Half e_shentsize; /* Section header table entry size */
Elf32_Half e_shnum; /* Section header table entry count */
Elf32_Half e_shstrndx; /* Section header string table index */
} Elf32_Ehdr;
typedef struct
{
unsigned char e_ident[EI_NIDENT]; /* Magic number and other info */
Elf64_Half e_type; /* Object file type */
Elf64_Half e_machine; /* Architecture */
Elf64_Word e_version; /* Object file version */
Elf64_Addr e_entry; /* Entry point virtual address */
Elf64_Off e_phoff; /* Program header table file offset */
Elf64_Off e_shoff; /* Section header table file offset */
Elf64_Word e_flags; /* Processor-specific flags */
Elf64_Half e_ehsize; /* ELF header size in bytes */
Elf64_Half e_phentsize; /* Program header table entry size */
Elf64_Half e_phnum; /* Program header table entry count */
Elf64_Half e_shentsize; /* Section header table entry size */
Elf64_Half e_shnum; /* Section header table entry count */
Elf64_Half e_shstrndx; /* Section header string table index */
} Elf64_Ehdr;
Elf32_Ehdr是32位系统的ELF文件头,Elf64_Ehdr为64位系统。
结构体内的解析可以在网上提供的文档找到详细的解释:http://pan.baidu.com/s/1hqkteF6
这里只讲解几个关键的:
e_phoff: 程序段头开始位置在文件的偏移
e_phnum:程序段头 个数
e_phentsize每一个程序段头大小
e_shoff节区头开始位置在文件偏移
e_shnum节区头个数
e_shentsize每一个节区头大小
e_shstrndx节区头名字对应的字符表的处于节区的位置。
这个有点不好理解。每一个节区都存储的一些内容,另外每一个节区都有一个节区头,每一个节区头都有对应的名字。
这个值是一个数字比如27,意思就是第27个节区存储的是节区头名字。
2、程序段头结构体
typedef struct
{
Elf32_Word p_type; /* Segment type */
Elf32_Off p_offset; /* Segment file offset */
Elf32_Addr p_vaddr; /* Segment virtual address */
Elf32_Addr p_paddr; /* Segment physical address */
Elf32_Word p_filesz; /* Segment size in file */
Elf32_Word p_memsz; /* Segment size in memory */
Elf32_Word p_flags; /* Segment flags */
Elf32_Word p_align; /* Segment alignment */
} Elf32_Phdr;
在ELF文件头有指明e_phoff对应这程序头的偏移量,偏移量开始你就能读取到e_phnum个结构段头。
可以根据程序段头找到对应的程序段,程序段头对应的解析查看相关文档,这里不做详细解析。