ELF文件格式(一)--ELF文件头
ELF文件有三种类型:relocatable file、executable file和shared object file。
relocatable file:可重定位的目标文件,可以和其他目标文件链接成可执行的目标文件或共享目标文件。
executable file:可执行的目标文件,通过exec函数执行该目标文件。
shared object file:共享目标文件,在执行可执行目标文件时动态链接器可以动态链接该文件。
2.ELF文件格式
ELF文件在链接和执行时具有不同的意义。
link view
|-----------------------|
| ELF header
|-----------------------|
| program header
|-----------------------|
| section1
|-----------------------|
| section2
|-----------------------|
| ...
|-----------------------|
| section header
|-----------------------|
execution view
|-----------------------|
| ELF header
|-----------------------|
| program header
|-----------------------|
| segment1
|-----------------------|
| segment2
|-----------------------|
| ...
|-----------------------|
| section header
|-----------------------|
ELF文件包含以下几个部分:ELF header、program header、section或segment和section header。
ELF header中记录了program header、section header的位置及大小等信息;是整个ELF文件的地图。
program header告诉系统怎样为可执行的目标文件创建进程,可执行的ELF文件必须有program header。
section中包含链接需要的指令、数据、符号表和重定位信息等。
section header中记录了每个section的地址入口、名字、大小等信息,可重定位的ELF文件必须有section header。
3.ELF文件头的格式
ELF header
|--------------------------|
| 16 | e_ident
|--------------------------|
| 2 | e_type
|--------------------------|
| 2 | e_machine
|--------------------------|
| 4 | e_version
|--------------------------|
| 4 | e_entry
|--------------------------|
| 4 | e_phoff
|--------------------------|
| 4 | e_shoff
|--------------------------|
| 4 | e_flags
|--------------------------|
| 2 | e_ehsize
|--------------------------|
| 2 | e_phentsize
|--------------------------|
| 2 | e_phnum
|--------------------------|
| 2 | e_shentsize
|--------------------------|
| 2 | e_shnum
|--------------------------|
| 2 | e_shstrndx
|--------------------------|
e_ident一共有16个字节。
1(BYTE) 1 1 1 1 1 1 9
| MAG0 | MAG1 | MAG2 | MAG3 | CLASS | DATA | VERSION | PAD ... |
第一个字节为0x7f,第二个字节为'E'的十六进制的ASCII码,第三个字节为'L',第四个字节为'F'。
CLASS字节表示文件的类型:1表示32位、2表示64位。
DATA字节表示大小端:1表示小端、2表示大端。
PAD共9个字节:用0填充。
3.2 e_type
e_type表示该目标文件的类型:1表示可重定位文件、2表示可执行文件、3表示共享目标文件、4表示Core文件。
3.3 e_machine
e_machine表示机器的体系结构。
1表示AT&T WE 32100
2表示SPARC
3表示Intel 80386
4表示Motorola 68000
5表示Motorola 88000
7表示Intel 80860
8表示MIPS RS3000
3.4 e_entry
e_entry表示可执行文件的地址入口。
3.5 e_phoff
e_phoff表示program header在ELF文件中的偏移量。
3.6 e_shoff
e_shoff表示section header在ELF文件中的偏移量。
3.7 e_ehsize
e_ehsize表示ELF header的大小。
3.8 e_phensize
e_phensize表示program header中每个表项的大小。
3.9 e_phnum
e_phnum表示program header中表项的个数。
3.10 e_shensize
e_shensize表示section header中每个表项的大小。
3.11 e_shnum
e_shnum表示section header中表项的个数。
3.12 e_shstrndx
e_shstrndx表示字符串节在section header中的索引。
附件:(读取ELF文件头,并解析)
#ifndef READ_ELF_H
#define READ_ELF_H
/* DEBUG */
//#define _DEBUG
#ifdef _DEBUG
#define PRINT printf
#else
#define PRINT
#endif
/* elf32_head: define the ELF header */
#define EI_NIDENT (16)
struct elf32_head {
unsigned char e_ident[EI_NIDENT]; /* the magic number */
unsigned short e_type; /* identify the object file type */
unsigned short e_machine; /* specify the machine architechture */
unsigned int e_version; /* identify the object file version*/
unsigned int e_entry; /* entry point address of the process */
unsigned int e_phoff; /* start of program header */
unsigned int e_shoff; /* start of section header */
unsigned int e_flags; /* flags */
unsigned short e_ehsize; /* size of the ELF header */
unsigned short e_phentsize; /* size of program header */
unsigned short e_phnum; /* number of program header */
unsigned short e_shentsize; /* size of section header */
unsigned short e_shnum; /* number of section header */
unsigned short e_shstrndx; /* section header string table index */
};
#define ELF_HEAD_SIZE sizeof(struct elf32_head)
/* e_ident: define the magic number
* 1(BYTE) 1 1 1 1 1 1 9
* |MAG0| |MAG1| |MAG2| |MAG3| |CLASS| |DATA| |VERSION| |PAD ...|
*/
#define EI_MAG0 (0) /* 0Xf7 */
#define EI_MAG1 (1) /* 'E' */
#define EI_MAG2 (2) /* 'L' */
#define EI_MAG3 (3) /* 'F' */
#define EI_CLASS (4)
#define EI_DATA (5)
#define EI_VERSION (6)
#define EI_PAD (7)
/* CLASS: identify the file's class */
#define ELF_CLASS_NONE (0) /* Invalid class*/
#define ELF_CLASS_32 (1) /* 32-bit objects */
#define ELF_CLASS_64 (2) /* 64-bit objects */
/* DATA: little or big endian */
#define ELF_DATA_NONE (0) /* Invalid data encoding */
#define ELF_DATA_LSB (1) /* little endian */
#define ELF_DATA_MSB (2) /* big endian */
/* VERSION: must be EV_CURRENT */
#define ELF_VERSION_CURRENT (1) /* must be EV_CURRENT */
/* PAD: set to zero */
#define ELF_PAD_VALUE (0) /* set to zero */
/* e_type: identify the 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_LOPROC (0Xff00) /* Processor-specific */
#define ET_HIPROC (0Xffff) /* Processor-specific */
/* e_machine: specify the machine architecture */
#define EM_NONE (0) /* No machine */
#define EM_M32 (1) /* AT&T WE 32100 */
#define EM_SPARC (2) /* SPARC */
#define EM_386 (3) /* Intel 80386 */
#define EM_68K (4) /* Motorola 68000 */
#define EM_88K (5) /* Motorola 88000 */
#define EM_860 (6) /* Intel 80860 */
#define EM_MIPS (7) /* MIPS RS3000 */
/* e_version: identify the object file version */
#define EV_NONE (0) /* Invalid version */
#define EV_CURRENT (1) /* Current version */
#endif
#include <stdio.h>
#include <fcntl.h>
#include "read_elf.h"
#define ARGC_NUM 2
static void read_elf_help(void)
{
printf("Usage: read_elf filename\n");
}
static void print_elf_head(struct elf32_head * elf_head)
{
int i = 0;
struct elf32_head *p_elf_head = NULL;
if (NULL != elf_head) {
p_elf_head = elf_head;
} else {
PRINT("P_ELF_HEAD is NULL\n");
return;
}
printf("ELF Header:\n");
/* the Magic */
printf(" Magic:");
for (i = 0; i < EI_NIDENT; i++) {
printf(" %02x", (p_elf_head->e_ident)[i]);
}
printf("\n");
/* the class */
printf("%-40s", " Class:");
switch ((p_elf_head->e_ident)[EI_CLASS]) {
case ELF_CLASS_NONE:
printf("Invalid class\n");
break;
case ELF_CLASS_32:
printf("ELF32\n");
break;
case ELF_CLASS_64:
printf("ELF64\n");
break;
default:
printf("0X%x (Unknown)\n", (p_elf_head->e_ident)[EI_CLASS]);
break;
}
/* the data */
printf("%-40s", " Data:");
switch ((p_elf_head->e_ident)[EI_DATA]) {
case ELF_DATA_NONE:
printf("Invalid data encoding\n");
break;
case ELF_DATA_LSB:
printf("little endian\n");
break;
case ELF_DATA_MSB:
printf("big endian\n");
break;
default:
printf("0X%x (Unknown)\n", (p_elf_head->e_ident)[EI_DATA]);
break;
}
/* the version */
printf("%-40s", " Version:");
if (ELF_VERSION_CURRENT == (p_elf_head->e_ident)[EI_VERSION]) {
printf("1 (current)\n");
} else {
printf("0X%x (Unknown)\n", (p_elf_head->e_ident)[EI_VERSION]);
}
/* the Type */
printf("%-40s", " Type:");
switch(p_elf_head->e_type) {
case ET_NONE:
printf("NONE\n");
break;
case ET_REL:
printf("REL\n");
break;
case ET_EXEC:
printf("EXEC\n");
break;
case ET_DYN:
printf("DYN\n");
break;
case ET_CORE:
printf("CORE\n");
break;
case ET_LOPROC:
printf("LOPROC\n");
break;
case ET_HIPROC:
printf("HIPROC\n");
break;
default:
printf("0X%x (Unknown)\n", p_elf_head->e_type);
break;
}
/* the Machine */
printf("%-40s", " Machine:");
switch (p_elf_head->e_machine) {
case EM_NONE:
printf("No machine\n");
break;
case EM_M32:
printf("AT&T WE 32100\n");
break;
case EM_SPARC:
printf("SPARC\n");
break;
case EM_386:
printf("Intel 80386\n");
break;
case EM_68K:
printf("Motorola 68000\n");
break;
case EM_88K:
printf("Motorola 88000\n");
break;
case EM_860:
printf("Intek 80860\n");
break;
case EM_MIPS:
printf("MIPS RS3000\n");
break;
default:
printf("0X%x (Unknown)\n", p_elf_head->e_machine);
break;
}
/* the Version */
printf("%-40s", " Version:");
switch (p_elf_head->e_version) {
case EV_NONE:
printf("Invalid version\n", p_elf_head->e_version);
break;
case EV_CURRENT:
printf("Current version\n", p_elf_head->e_version);
break;
default:
printf("0X%x (Unknown)\n", p_elf_head->e_version);
break;
}
/* the entry point of process */
printf("%-40s", " Entry point address:");
printf("0X%x\n", p_elf_head->e_entry);
/* the start of program headers */
printf("%-40s", " Start of program headers:");
printf("%d (bytes)\n", p_elf_head->e_phoff);
/* the start of section headers */
printf("%-40s", " Start of section headers:");
printf("%d (bytes)\n", p_elf_head->e_shoff);
/* the flags */
printf("%-40s", " Flags: ");
printf("0X%x\n", p_elf_head->e_flags);
/* the size of this header */
printf("%-40s", " Size of this header:");
printf("%d (bytes)\n", p_elf_head->e_ehsize);
/* the size of program headers */
printf("%-40s", " Size of program headers:");
printf("%d (bytes)\n", p_elf_head->e_phentsize);
/* the number of program headers */
printf("%-40s", " Number of program headers:");
printf("%d\n", p_elf_head->e_phnum);
/* the size of section headers */
printf("%-40s", " Size of section headers:");
printf("%d (bytes)\n", p_elf_head->e_shentsize);
/* the number of section headers */
printf("%-40s", " Number of section headers:");
printf("%d\n", p_elf_head->e_shnum);
/* the section header string table index */
printf("%-40s", " Section header string table index:");
printf("%d\n", p_elf_head->e_shstrndx);
}
int main(int argc, const char *argv[])
{
int fd = 0;
char buf[ELF_HEAD_SIZE] = {0};
struct elf32_head *p_elf_head = NULL;
if (ARGC_NUM != argc) {
read_elf_help();
return(0);
}
if (-1 == (fd = open(argv[1], O_RDONLY))) {
printf("open %s ERR!\n", argv[1]);
}
if (ELF_HEAD_SIZE != read(fd, buf, ELF_HEAD_SIZE)) {
printf("ELF head length is incorrect!\n");
return(0);
}
p_elf_head = (struct elf32_head *) buf;
print_elf_head(p_elf_head);
return(0);
}