zoukankan      html  css  js  c++  java
  • elf文件结构解析

    elf文件结构解析

    elf文件格式,许多文件类型都是elf格式,比如.ko、.so、.o,vmlinux也是这种格式

    如下图是elf文件结构:

     

    查看是否为elf文件,使用file cmd

    file slub_debug_test_module.ko
    slub_debug_test_module.ko: ELF 64-bit LSB  relocatable, ARM aarch64, version 1 (SYSV), not stripped

     查看elf file header

    readelf -h xxx.ko

    ELF Header:
    Magic: 7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00
    
    Class: ELF64
    
    Data: 2's complement, little endian
    
    Version: 1 (current)
    
    OS/ABI: UNIX - System V
    
    ABI Version: 0
    
    Type: REL (Relocatable file)
    
    Machine: AArch64
    
    Version: 0x1
    
    Entry point address: 0x0
    
    Start of program headers: 0 (bytes into file)
    
    Start of section headers: 122120 (bytes into file)
    
    Flags: 0x0
    
    Size of this header: 64 (bytes)
    
    Size of program headers: 0 (bytes)
    
    Number of program headers: 0
    
    Size of section headers: 64 (bytes)
    
    Number of section headers: 35
    
    Section header string table index: 33

     上述结果在code里对应如下结构体:

    #define EI_NIDENT    16
    typedef struct elf32_hdr{
      unsigned char    e_ident[EI_NIDENT];  //开始的16个字节
      Elf32_Half    e_type;  //文件类型
      Elf32_Half    e_machine;  //运行的机器类型
      Elf32_Word    e_version;  //版本
      Elf32_Addr    e_entry;  //程序入口地址
      Elf32_Off    e_phoff;  //程序头表在文件中的偏移
      Elf32_Off    e_shoff;  //节头表在文件中的偏移
      Elf32_Word    e_flags;  //标记
      Elf32_Half    e_ehsize;  //elf文件头大小
      Elf32_Half    e_phentsize;  //程序头表项的大小
      Elf32_Half    e_phnum;  //程序头表中表项项的个数
      Elf32_Half    e_shentsize;  //节头表项大小
      Elf32_Half    e_shnum;  //节头表中表项的个数
      Elf32_Half    e_shstrndx;  //节头表的字符串节所在节头表中下标
    } Elf32_Ehdr;

    获取elf文件里包含的section描述table:

    readelf -WS xxx.ko     #W option表示将一个section的结果以一行显示,在没有一行显示的情况下可以加这个option

    There are 35 section headers, starting at offset 0x1dd08:
    Section Headers:
    
    [Nr] Name Type Address Off Size ES Flg Lk Inf Al
    
    [ 0] NULL 0000000000000000 000000 000000 00 0 0 0
    
    [ 1] .text PROGBITS 0000000000000000 000040 0000ac 00 AX 0 0 4
    
    [ 2] .rela.text RELA 0000000000000000 0000f0 000168 18 I 32 1 8
    
    [ 3] .data PROGBITS 0000000000000000 000258 000100 00 WA 0 0 8
    
    [ 4] .rela.data RELA 0000000000000000 000358 000048 18 I 32 3 8
    
    [ 5] .bss NOBITS 0000000000000000 0003a0 000000 00 WA 0 0 1
    
    [ 6] .init.text PROGBITS 0000000000000000 0003a0 00009c 00 AX 0 0 4
    
    [ 7] .rela.init.text RELA 0000000000000000 000440 000228 18 I 32 6 8
    
    [ 8] .exit.text PROGBITS 0000000000000000 000668 000034 00 AX 0 0 4
    
    [ 9] .rela.exit.text RELA 0000000000000000 0006a0 000090 18 I 32 8 8
    
    [10] .modinfo PROGBITS 0000000000000000 000730 000086 00 A 0 0 1
    
    [11] .rodata.str1.1 PROGBITS 0000000000000000 0007b6 0000d0 01 AMS 0 0 1
    
    [12] .debug_loc PROGBITS 0000000000000000 000886 00027d 00 0 0 1
    
    [13] .rela.debug_loc RELA 0000000000000000 000b08 000108 18 I 32 12 8
    
    [14] .debug_abbrev PROGBITS 0000000000000000 000c10 0005aa 00 0 0 1
    
    [15] .debug_info PROGBITS 0000000000000000 0011ba 008b67 00 0 0 1
    
    [16] .rela.debug_info RELA 0000000000000000 009d28 00dda0 18 I 32 15 8
    
    [17] .debug_ranges PROGBITS 0000000000000000 017ac8 000040 00 0 0 1
    
    [18] .rela.debug_ranges RELA 0000000000000000 017b08 000090 18 I 32 17 8
    
    [19] .debug_str PROGBITS 0000000000000000 017b98 004739 01 MS 0 0 1
    
    [20] .comment PROGBITS 0000000000000000 01c2d1 00009d 01 MS 0 0 1
    
    [21] .debug_line PROGBITS 0000000000000000 01c36e 000ba8 00 0 0 1
    
    [22] .rela.debug_line RELA 0000000000000000 01cf18 000048 18 I 32 21 8
    
    [23] .debug_frame PROGBITS 0000000000000000 01cf60 0000a0 00 0 0 8
    
    [24] .rela.debug_frame RELA 0000000000000000 01d000 0000c0 18 I 32 23 8
    
    [25] __mcount_loc PROGBITS 0000000000000000 01d0c0 000018 08 A 0 0 8
    
    [26] .rela__mcount_loc RELA 0000000000000000 01d0d8 000048 18 I 32 25 8
    
    [27] .note.Linux NOTE 0000000000000000 01d120 000018 00 A 0 0 4
    
    [28] .gnu.linkonce.this_module PROGBITS 0000000000000000 01d140 000340 00 WA 0 0 64
    
    [29] .rela.gnu.linkonce.this_module RELA 0000000000000000 01d480 000030 18 I 32 28 8
    
    [30] .note.gnu.build-id NOTE 0000000000000000 01d4b0 000018 00 A 0 0 4
    
    [31] .note.GNU-stack PROGBITS 0000000000000000 01d4c8 000000 00 0 0 1
    
    [32] .symtab SYMTAB 0000000000000000 01d4c8 0004c8 18 34 37 8
    
    [33] .shstrtab STRTAB 0000000000000000 01d990 0001ce 00 0 0 1
    
    [34] .strtab STRTAB 0000000000000000 01db5e 0001a9 00 0 0 1
    
    Key to Flags:
    
    W (write), A (alloc), X (execute), M (merge), S (strings)
    
    I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
    
    O (extra OS processing required) o (OS specific), p (processor specific)

     需要注意的是,rodata等其它section在一个 elf文件里可能不止一个,有多个,比如如下:

     [1057] .rodata..Lswitch. PROGBITS         0000000000000000  0059c558
      [1062] .rodata..L__const PROGBITS         0000000000000000  0059c5b0
      [1069] .rodata..Lswitch. PROGBITS         0000000000000000  0059c6a0
      [1070] .rodata..Lanon.22 PROGBITS         0000000000000000  0059c6e0
      [1071] .rodata..Lanon.22 PROGBITS         0000000000000000  0059c730
      [1072] .rodata..Lswitch. PROGBITS         0000000000000000  0059c75c

    一个section header(SH)在code里使用如下结构体来描述:

    typedef struct elf32_shdr {
      Elf32_Word    sh_name;  //节的名字,在符号表中的下标
      Elf32_Word    sh_type;  //节的类型,描述符号,代码,数据,重定位等
      Elf32_Word    sh_flags;  //读写执行标记
      Elf32_Addr    sh_addr;  //节在执行时的虚拟地址
      Elf32_Off    sh_offset;  //节在文件中的偏移量
      Elf32_Word    sh_size;  //节的大小
      Elf32_Word    sh_link;  //其它节的索引
      Elf32_Word    sh_info;  //节的其它信息
      Elf32_Word    sh_addralign;  //节对齐
      Elf32_Word    sh_entsize;  //当前section相对于core_layout/init_layout base地址的offset,根据这个offset,用于将efl文件(vmalloc内存)里的该section copy至core_layout/init_layout(module区)里对应位置
    } Elf32_Shdr;

    获取elf文件里的symbol table

    readelf -s xxx.ko

    Symbol table '.symtab' contains 51 entries:
    Num: Value Size Type Bind Vis Ndx Name
    
    0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND
    
    1: 0000000000000000 0 FILE LOCAL DEFAULT ABS slub_debug_test_drv.c
    
    2: 0000000000000000 0 NOTYPE LOCAL DEFAULT 6 $x
    
    3: 0000000000000000 256 OBJECT LOCAL DEFAULT 3 hello_flops
    
    4: 0000000000000000 0 NOTYPE LOCAL DEFAULT 8 $x
    
    5: 0000000000000000 0 NOTYPE LOCAL DEFAULT 1 $x
    
    6: 0000000000000000 136 FUNC LOCAL DEFAULT 1 hello_write
    
    7: 0000000000000088 36 FUNC LOCAL DEFAULT 1 hello_open
    
    8: 0000000000000000 12 OBJECT LOCAL DEFAULT 10 __UNIQUE_ID_license10
    
    9: 0000000000000000 0 NOTYPE LOCAL DEFAULT 3 $d
    
    10: 0000000000000010 0 NOTYPE LOCAL DEFAULT 23 $d
    
    11: 0000000000000000 0 SECTION LOCAL DEFAULT 1
    
    12: 0000000000000000 0 SECTION LOCAL DEFAULT 3
    
    13: 0000000000000000 0 SECTION LOCAL DEFAULT 5
    
    14: 0000000000000000 0 SECTION LOCAL DEFAULT 6
    
    15: 0000000000000000 0 SECTION LOCAL DEFAULT 8
    
    16: 0000000000000000 0 SECTION LOCAL DEFAULT 10
    
    17: 0000000000000000 0 SECTION LOCAL DEFAULT 12
    
    18: 0000000000000000 0 SECTION LOCAL DEFAULT 14
    
    19: 0000000000000000 0 SECTION LOCAL DEFAULT 15
    
    20: 0000000000000000 0 SECTION LOCAL DEFAULT 17
    
    21: 0000000000000000 0 SECTION LOCAL DEFAULT 21
    
    22: 0000000000000000 0 SECTION LOCAL DEFAULT 23
    
    23: 0000000000000000 0 SECTION LOCAL DEFAULT 25
    
    24: 0000000000000000 0 FILE LOCAL DEFAULT ABS slub_debug_test_module.mo
    
    25: 0000000000000000 24 OBJECT LOCAL DEFAULT 27 _note_6
    
    26: 0000000000000000 0 NOTYPE LOCAL DEFAULT 27 $d
    
    27: 000000000000000c 50 OBJECT LOCAL DEFAULT 10 __UNIQUE_ID_vermagic10
    
    28: 000000000000003e 28 OBJECT LOCAL DEFAULT 10 __UNIQUE_ID_name11
    
    29: 0000000000000000 0 NOTYPE LOCAL DEFAULT 28 $d
    
    30: 000000000000005a 9 OBJECT LOCAL DEFAULT 10 __module_depends
    
    31: 0000000000000063 35 OBJECT LOCAL DEFAULT 10 __UNIQUE_ID_srcversion12
    
    32: 0000000000000000 0 SECTION LOCAL DEFAULT 27
    
    33: 0000000000000000 0 SECTION LOCAL DEFAULT 28
    
    34: 0000000000000000 0 SECTION LOCAL DEFAULT 11
    
    35: 0000000000000000 0 SECTION LOCAL DEFAULT 19
    
    36: 0000000000000000 0 SECTION LOCAL DEFAULT 20
    
    37: 0000000000000000 156 FUNC GLOBAL DEFAULT 6 init_module
    
    38: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND _mcount
    
    39: 0000000000000000 0 NOTYPE GLOBAL DEFAULT UND __register_chrdev
    ...

    以下面的例子说明下,

    readelf -s xxx.ko |grep proc_mpoolinfo_operations
      5510: 0000000000114360   256 OBJECT  GLOBAL DEFAULT    6 proc_mpoolinfo_operations

     行为例,这行是一个object,比如是一个结构体,256是这个结构体的size,后面的6表示这个symbol是位于index为6的section里,一般是.bss或者.data section,数字3是在ndx column。这个很方便,以后想知道一个结构体的size用这种方式很快捷。

    第二列表示此symbol在这个section(.data or .bss)里的offset,这个在加载ko时将根据这个offset加上section base addr确定此symbol的execution addr,这部分逻辑在simplify_symbols()

    dump elf文件里的某个section

      -x --hex-dump=<number|name>
                             Dump the contents of section <number|name> as bytes
      -p --string-dump=<number|name>
                             Dump the contents of section <number|name> as strings
      -R --relocated-dump=<number|name>
                             Dump the contents of section <number|name> as relocated bytes

    上述number、name分别是readelf -S结果了的Nr、name列,可以指定number或者name,dump某个section直接看这个section里的数据是什么

    上述部分参考如下blog:

    https://www.cnblogs.com/chengxuyuancc/p/3474623.html

    elf64_sym structure

    typedef struct elf64_sym {
      Elf64_Word st_name;        /* Symbol name, index in string tbl */  /* strtab是所有symbol name string的table,所有的symbol name string都存在这个table里,这个table其实就是一个char*数组,st_name是某一个string在这个数组里的offset,下一个string则是在上一个string
                                               的offset加上上一个string len作为它的offset */
    unsigned char st_info; /* Type and binding attributes */ unsigned char st_other; /* No defined meaning, 0 */ Elf64_Half st_shndx; /* Associated section index */ /* 表示这个symbol是存放在哪个section里,这个section的index,比如函数symbol会存放在.text section;而变量symbol则会存在.data section */ Elf64_Addr st_value; /* Value of the symbol */ /* 这个symbol在所在的section里的offset */ Elf64_Xword st_size; /* Associated symbol size */ /* symbol size */ } Elf64_Sym;

    elf section

    .strtab,存放symbol name string的table

    .shstrtab,存放section name string的table

    .symtab,存放symbol描述信息的table,这个table会引用.strtab,里面的st_name表示这个symbol name string在strtab里的offset

  • 相关阅读:
    C# tcp发送十六进制数据
    WPF中通过AForge实现USB摄像头拍照
    借鉴过的别人的帖子之C#篇
    C# 连续的语音识别
    C# NAudio 录音
    AS3 水波纹
    ARM多核心集群服务器
    RK3399Pro Android Rock-X 人工智能开发系列(2)
    智能化连锁门店解决方案
    RK3399Pro Android Rock-X 人工智能开发系列(1)
  • 原文地址:https://www.cnblogs.com/aspirs/p/15522256.html
Copyright © 2011-2022 走看看