鸳鸯被里成双夜
一树梨花压海棠
从libelfin的例子和网上各种资料我也没找到怎么读取elf文件的头部,非常懵逼呀!
其实有种很简单的方法:
不过这是从命令行获取的,肯定是不够的,实际上elf可执行文件/共享库文件都可以当成二进制文件读取。
关于共享库文件和可执行文件
在GCC/G++低版本和CLANG编译的可执行elf文件,其实都是EXEC类型的,其实就是上图中说到的类型,是通过readelf命令读取elf文件的头部来实现的。
可以看一下elf文件的头部包括哪些内容,这个其实对应的是/usr/include/elf.h
中的一个结构体:
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;
这里就不一一翻译了,重点关注的是e_type
,e_type
对应的几个值:
/* Legal values for e_type (object file type). */
#define ET_NONE 0 /* No file type */
#define ET_REL 1 /* Relocatable file */
#define ET_EXEC 2 /* Executable file */
#define ET_DYN 3 /* Shared object file */
#define ET_CORE 4 /* Core file */
#define ET_NUM 5 /* Number of defined types */
#define ET_LOOS 0xfe00 /* OS-specific range start */
#define ET_HIOS 0xfeff /* OS-specific range end */
#define ET_LOPROC 0xff00 /* Processor-specific range start */
#define ET_HIPROC 0xffff /* Processor-specific range end */
也就是elf文件类型有多种,有常见的重定位文件,可执行文件,共享库文件,coredump文件等。这里主要关注的是可执行文件和共享库文件。
在GCC高版本中,编译得到的目标文件其实是共享库文件,以及我们常见的.so动态库文件也是共享库文件,这里用readelf
做个验证。
比如动态库文件:
在Type对应的属性是DYN(Shared object file)
,确实是共享库文件。
再比如我用ubuntu 18.04中的gcc 7.4编写的hello word:
可以看到,也是共享库文件。
当然这种方式对于有些实现某些需求不太合适,比如想要在代码中判断elf文件的类型,当然可以用system()
函数执行readelf -h <elffile>
命令,然后获取命令行输出,但是显然效率和可靠性都是问题。
C/C++读取ELF文件头部信息
其实可以直接把elf文件当成二进制文件来读取,而64位中elf文件的前64字节就是elf的头部。
#include <elf.h>
#include <iostream>
#include <fcntl.h>
#include <unistd.h>
int main() {
char file[] = "/home/bbkgl/vimcode/server";
int fd = open(file, O_RDONLY);
Elf64_Ehdr header;
ssize_t ret = read(fd, &header, sizeof(Elf64_Ehdr));
close(fd);
if (fd > 0 && ret > 0) {
switch (header.e_type) {
case ET_DYN:
printf("DYN\n");
break;
case ET_EXEC:
printf("EXEC\n");
break;
default:
printf("OTHER\n");
break;
}
}
return 0;
}
代码相当简单,看下输出:
如果把更换elf文件为之前的helloword,再看输出:
int main() {
char file[] = "/home/bbkgl/vimcode/helloworld";
int fd = open(file, O_RDONLY);
...
}
简单2333!