ELF文件格式(一)--ELF文件头

本文深入探讨了ELF文件的三种类型、结构和组成部分,详细解释了ELF头的各部分及其作用,提供了ELF文件解析的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

ELF文件格式(一)--ELF文件头


1.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
|--------------------------|

3.1 e_ident
    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);
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值