• ELF文件格式入门


    什么是ELF

    ELF(Executable and Linking Format),即“可执行可连接格式”,最初由 UNIX系统实验室做为应用程序二进制接口(ABI)的一部分而制定和发布。简单说就是一种文件格式。

    ELF文件类型

    (1)可重定位文件, 一般就是源文件编译生成的".o"文件,这些文件用于与其它目标文件进行链接生成可执行文件或动态链接库

    (2)共享目标文件, 即动态链接库文件, 就是".so"文件。

    (3)可执行文件, 经过链接的,可以执行的程序文件。

    ELF文件格式

    图片

    因为ELF格式的文件有些是用来连接的,有些是可以执行的。所以上面中从“连接”和“运行”两个视角来看ELF文件的格式。

    ELF文件主要由四部分组成:

    (1)ELF文件头

    (2)程序头表

    (3)节(Section)或段

    (4)节头表或段头表

    1、ELF文件头

    描述文件的主要特性:类型,CPU架构,入口地址,现有部分的大小和偏移等。

    文件头数据结构如下:

    #define EI_NIDENT  16
    
    typedef struct elf64_hdr {
      unsigned char  e_ident[EI_NIDENT]; //魔术字,用来确认文件是否是一个ELF文件
      Elf64_Half e_type;  //文件类型,比如可重定位文件,可执行文件等
      Elf64_Half e_machine; //处理器架构
      Elf64_Word e_version; //ELF文件格式的版本
      Elf64_Addr e_entry;   //程序入口的虚拟地址
      Elf64_Off e_phoff;    //程序头表开始处在文件中的偏移量
      Elf64_Off e_shoff;   //节头表开始处在文件中的偏移量
      Elf64_Word e_flags;  //处理器特定的标志位
      Elf64_Half e_ehsize; //ELF文件头的大小
      Elf64_Half e_phentsize; //在程序头表中每一个表项的大小
      Elf64_Half e_phnum; //程序头表中总共有多少个表项
      Elf64_Half e_shentsize; //节头表中每一个表项的大小
      Elf64_Half e_shnum;  //节头表中每一个表项的大小
      Elf64_Half e_shstrndx; //节头表中与节名字表相对应的表项的索引
    } Elf64_Ehdr;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    2、程序头表

    程序头表就是一个数组,里面的每个元素都是一个程序头。每一个程序头描述了一个“段(segment)”。一个“段(segment)”包含一个或者多个“节(section)”。

    程序头的数据结构如下:

    typedef struct elf64_phdr {
      Elf64_Word p_type;   //段的类型
      Elf64_Word p_flags;  //段属性,处理器特定的标志位
      Elf64_Off p_offset;  //段内容在文件中的位置
      Elf64_Addr p_vaddr;  //段内容的开始位置在进程空间中的虚拟地址
      Elf64_Addr p_paddr;  //段内容的开始位置在进程空间中的物理地址
      Elf64_Xword p_filesz;//段内容在文件中的大小
      Elf64_Xword p_memsz; //段内容在内存中的大小
      Elf64_Xword p_align; //段对齐
    } Elf64_Phdr;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    *注意: 程序头只对可执行文件或共享目标文件有意义,对于其它类型的目标文件,该信息可以忽略。

    3、节头表

    节头表也是一个数组。节头表的每一个表项描述了节的信息,通过每一个表项可以定位到对应的节。

    节头的数据结构如下:

    typedef struct elf64_shdr {
      Elf64_Word sh_name; //节的名称
      Elf64_Word sh_type; //节的类型
      Elf64_Xword sh_flags;//节的属性
      Elf64_Addr sh_addr; //执行时节的虚拟地址
      Elf64_Off sh_offset;//节在文件中的位置
      Elf64_Xword sh_size;//节的大小
      Elf64_Word sh_link; //索引值,指向节头表中本节所对应的位置
      Elf64_Word sh_info; //节的附加信息
      Elf64_Xword sh_addralign;//节对齐
      Elf64_Xword sh_entsize;  //有一些节的内容是一张表,
                             //其中每一个表项的大小是固定的,比如符号表。
                             //对于这种表来说,本成员指定其每一个表项的大小。
    } Elf64_Shdr;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4.节(Section)

    节里面就是代码和数据。比如".text", “.data” , ".rodata"等。如下图:

    图片

    • .text : 就是存放代码的节

    • .rodata: 存放只读数据的节

    • .data: 存放读写数据的节

    在 ELF文件中有一些特定的节是预定义好的,其内容是指令代码或者控制信息。比如:“.text”, “.bss”, ".data"等都是预定义的节。

    应用程序也可以构造自己的段,但最好不要取与上述系统已定义的节相同的名字,也不要取以点号开头的名字,以避免潜在的冲突。

    更多定义可参考下面文档:

    https://paper.seebug.org/papers/Archive/refs/elf/Understanding_ELF.pdf

    实例分析

    我们自己写一个应用程序,然后通过readelf命令来分析elf文件。

    (1)读取可执行文件的ELF文件头

    readelf -h timer
    
    • 1

    图片

    这些解析完的参数就是对应上面的ELF文件头的结构体。

    上面的文件类型就是可执行文件。

    (2)读取.o文件的ELF文件头

    readelf -h timer.o
    
    • 1

    图片

    上面的文件类型为可重定位文件。

    (3)读取可执行文件的程序头

    readelf -l timer
    
    • 1

    图片

    从上面可以看到总共有9个程序头,也就有9个段。这9个段和节之间的映射关系如下:

    图片

    总结

    看完这些是不是觉得没什么用,好像开发中也很少用到。但如果有一天你的项目需要你写链接脚本时,可能会从中找到一些有用的东西!

    图片

    往期推荐:

    【通信协议】一文搞懂SPI

    嵌入式到底应该选择驱动开发,还是应用开发?

    【通信协议】一文搞懂I2C

    推荐几款串口监控软件

    一文搞懂UART

  • 相关阅读:
    深入实现 MyBatis 底层机制的任务阶段 6-实现任务阶段 6- 在 WyxConfiguration, 读取 XxxMapper.xml,能够创建 MappperBean 对象
    记一次 .NET 某药厂业务系统 CPU爆高分析
    x64内核实验2-段机制的变化
    Nexus-3.41.1安装
    以往我们认识的产业互联网,只是以消费互联网的替代者的身份出现
    下一代 CI/CD:利用 Tekton 和 ArgoCD 实现云原生自动化
    喜报 | 祝贺璞华科技通过CMMI Lv5 等级复审!
    基于docker构建容器镜像
    c++学生成绩管理系统
    己二酸行业发展趋势
  • 原文地址:https://blog.csdn.net/u012041204/article/details/126914506