美文网首页
编译与链接——探究ELF文件结构

编译与链接——探究ELF文件结构

作者: 侠之大者_7d3f | 来源:发表于2021-05-07 23:28 被阅读0次

    前言

    在之前的学习中了解到GCC编译Cpp文件生成的目标文件(.o) 中的各个段(section)的含义, 重点实践了代码段数据段 这些常见的段。对于一个完整的ELF文件,除了各个之外,还包含了一些其他附属信息等待挖掘。


    测试环境

    • Ubuntu 20.04
    • VSCode
    • GCC >= 7.5.0

    ELF文件的结构组成

    • ELF header: ELF的头文件,包含整个文件的基本信息描述
    • 段表(Section Header Table): 包含elf文件各个段的信息
    • 符号表(Symbol Table)

    ELF文件的查看分析工具: readelf 命令

    -a --all               Equivalent to: -h -l -S -s -r -d -V -A -I
      -h --file-header       Display the ELF file header
      -l --program-headers   Display the program headers
         --segments          An alias for --program-headers
      -S --section-headers   Display the sections' header
         --sections          An alias for --section-headers
      -g --section-groups    Display the section groups
      -t --section-details   Display the section details
      -e --headers           Equivalent to: -h -l -S
      -s --syms              Display the symbol table
         --symbols           An alias for --syms
      --dyn-syms             Display the dynamic symbol table
      -n --notes             Display the core notes (if present)
      -r --relocs            Display the relocations (if present)
      -u --unwind            Display the unwind info (if present)
      -d --dynamic           Display the dynamic section (if present)
      -V --version-info      Display the version sections (if present)
      -A --arch-specific     Display architecture specific information (if any)
      -c --archive-index     Display the symbol/file index in an archive
    

    继续采用之前的程序: SimpleSection.cpp

    /**
     * @file SimpleSectipn.cpp
     * @author your name (you@domain.com)
     * @brief 
     * @version 0.1
     * @date 2021-04-27
     * 
     * @copyright Copyright (c) 2021
     * 
     */
    
    int printf(const char* format, ... );
    
    int global_init_var = 84;
    int global_uninit_var;
    
    void func1(int i){
        printf("%d\n", i);
    }
    
    // 使用GCC的扩展功能,制定函数到 ABC段
    __attribute__((section("ABC"))) void func2(){
        printf("Hello,world!\n");
    }
    
    __attribute__((section("DEF"))) int g_index = 12345;
    
    int main(){
        static int static_var = 85;
        static int static_var2;
    
        int a = 1;
        int b;
    
        func1(static_var + static_var2 + a + b);
    
        return a;
    }
    

    ELF 头文件(ELF Header)

    readelf -h xxx.o 读取elf文件的头部信息,主要包含内容:

    • ELF 魔术 (就是一些特定数字)
    • 数据存储方式: 大端、小端
    • ABI 版本信息
    • 运行平台: unix, amd64 x86-64
    • 段的数量,长度, 17个段
    readelf -h SimpleSectipn.o             
    ELF 头:
      Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
      类别:                              ELF64
      数据:                              2 补码,小端序 (little endian)
      Version:                           1 (current)
      OS/ABI:                            UNIX - System V
      ABI 版本:                          0
      类型:                              REL (可重定位文件)
      系统架构:                          Advanced Micro Devices X86-64
      版本:                              0x1
      入口点地址:               0x0
      程序头起点:          0 (bytes into file)
      Start of section headers:          1488 (bytes into file)
      标志:             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:         17
      Section header string table index: 16
    

    段表 (Section Header Table)

    段表用于记录各个段的信息,比如段的字节大小,段名称,读写权限等。段表并不是段本身,段本身是指.text, .data, .rodata 等。
    readelf -S xxx.o 读取段表信息, 下面读取的结果段的编号从0~16, 总共17个段, 常见的段: .text, .data, .rodata, .bss, .comment, 以及自定义的2个段 ABC, DEF。 标号为0的段大小为NULL, 实际上有效的段为1~16

    There are 17 section headers, starting at offset 0x5d0:
    
    节头:
      [号] 名称              类型             地址              偏移量
           大小              全体大小          旗标   链接   信息   对齐
      [ 0]                   NULL             0000000000000000  00000000
           0000000000000000  0000000000000000           0     0     0
      [ 1] .text             PROGBITS         0000000000000000  00000040
           000000000000005f  0000000000000000  AX       0     0     1
      [ 2] .rela.text        RELA             0000000000000000  00000458
           0000000000000078  0000000000000018   I      14     1     8
      [ 3] .data             PROGBITS         0000000000000000  000000a0
           0000000000000008  0000000000000000  WA       0     0     4
      [ 4] .bss              NOBITS           0000000000000000  000000a8
           0000000000000008  0000000000000000  WA       0     0     4
      [ 5] .rodata           PROGBITS         0000000000000000  000000a8
           0000000000000012  0000000000000000   A       0     0     1
      [ 6] ABC               PROGBITS         0000000000000000  000000ba
           000000000000001c  0000000000000000  AX       0     0     1
      [ 7] .relaABC          RELA             0000000000000000  000004d0
           0000000000000030  0000000000000018   I      14     6     8
      [ 8] DEF               PROGBITS         0000000000000000  000000d8
           0000000000000004  0000000000000000  WA       0     0     4
      [ 9] .comment          PROGBITS         0000000000000000  000000dc
           000000000000002b  0000000000000001  MS       0     0     1
      [10] .note.GNU-stack   PROGBITS         0000000000000000  00000107
           0000000000000000  0000000000000000           0     0     1
      [11] .note.gnu.propert NOTE             0000000000000000  00000108
           0000000000000020  0000000000000000   A       0     0     8
      [12] .eh_frame         PROGBITS         0000000000000000  00000128
           0000000000000078  0000000000000000   A       0     0     8
      [13] .rela.eh_frame    RELA             0000000000000000  00000500
           0000000000000048  0000000000000018   I      14    12     8
      [14] .symtab           SYMTAB           0000000000000000  000001a0
           0000000000000210  0000000000000018          15    14     8
      [15] .strtab           STRTAB           0000000000000000  000003b0
           00000000000000a7  0000000000000000           0     0     1
      [16] .shstrtab         STRTAB           0000000000000000  00000548
           0000000000000081  0000000000000000           0     0     1
    

    重定位表 (Relocation Table)

    readelf 输出的结果中, [1] 段的类型为RELA重定位

    [1]  .rela.text        RELA        
    

    符号表 (Symbol Table)

    符号表 对于链接时候比较重要, 经常会遇到链接时候的一些错误undefined reference 错误, 和符号表有很大的关系。
    查看目标文件的符号表nm 命令:
    C++代码中的变量名称:g_index, global_init_var, 等 以及函数名称: main, func1, func2, 程序中调用了标准库的函数printf, printf显然不在SimpleSection.cpp中定义, 因此printf为外部符号

    nm SimpleSectipn.o  
    0000000000000000 D g_index
    0000000000000000 D global_init_var
                     U _GLOBAL_OFFSET_TABLE_
    0000000000000000 B global_uninit_var
    0000000000000028 T main
    0000000000000000 T _Z5func1i
    0000000000000000 T _Z5func2v
                     U _Z6printfPKcz
    0000000000000004 d _ZZ4mainE10static_var
    0000000000000004 b _ZZ4mainE11static_var2
    

    也可以采用 readelf -s xxx.o 查看符号表的信息

    
    readelf -s SimpleSectipn.o 
    
    Symbol table '.symtab' contains 22 entries:
       Num:    Value          Size Type    Bind   Vis      Ndx Name
         0: 0000000000000000     0 NOTYPE  LOCAL  DEFAULT  UND 
         1: 0000000000000000     0 FILE    LOCAL  DEFAULT  ABS SimpleSectipn.cpp
         2: 0000000000000000     0 SECTION LOCAL  DEFAULT    1 
         3: 0000000000000000     0 SECTION LOCAL  DEFAULT    3 
         4: 0000000000000000     0 SECTION LOCAL  DEFAULT    4 
         5: 0000000000000000     0 SECTION LOCAL  DEFAULT    5 
         6: 0000000000000000     0 SECTION LOCAL  DEFAULT    6 
         7: 0000000000000000     0 SECTION LOCAL  DEFAULT    8 
         8: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    3 _ZZ4mainE10static_var
         9: 0000000000000004     4 OBJECT  LOCAL  DEFAULT    4 _ZZ4mainE11static_var2
        10: 0000000000000000     0 SECTION LOCAL  DEFAULT   10 
        11: 0000000000000000     0 SECTION LOCAL  DEFAULT   11 
        12: 0000000000000000     0 SECTION LOCAL  DEFAULT   12 
        13: 0000000000000000     0 SECTION LOCAL  DEFAULT    9 
        14: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    3 global_init_var
        15: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    4 global_uninit_var
        16: 0000000000000000    40 FUNC    GLOBAL DEFAULT    1 _Z5func1i
        17: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _GLOBAL_OFFSET_TABLE_
        18: 0000000000000000     0 NOTYPE  GLOBAL DEFAULT  UND _Z6printfPKcz
        19: 0000000000000000    28 FUNC    GLOBAL DEFAULT    6 _Z5func2v
        20: 0000000000000000     4 OBJECT  GLOBAL DEFAULT    8 g_index
        21: 0000000000000028    55 FUNC    GLOBAL DEFAULT    1 main
    

    相关文章

      网友评论

          本文标题:编译与链接——探究ELF文件结构

          本文链接:https://www.haomeiwen.com/subject/crkydltx.html