浅析ELF文件

概述

ELF: Executable and Linkable Format

翻译过来就是可执行可链接格式,Follow这种格式的文件就叫ELF文件

简单的说就是一种特定格式的文件,通过预先设置的这种格式规范来达到如下目的

  • 告诉编译器怎么产生目标文件
  • 告诉链接器怎么链接目标文件产生可执行文件
  • 告诉加载器怎么加载可执行文件并运行它

事实上计算机专家就是为了回答上面描述的三个问题而设计了目前这个跨平台(CPU/OS)的ELF文件格式

这就是需求决定了数据结构,数据结构则源于需求,一个典型的ELF文件格式如下

ELF格式

我们可以看见主要包含

  1. ELF Header
  2. Program Header Table
  3. Section Header Table
  4. Segment (section0 section1 ....)
              +-----------------+
         +----| ELF File Header |----+
         |    +-----------------+    |
         v                           v
 +-----------------+      +-----------------+
 | Program Headers |      | Section Headers |
 +-----------------+      +-----------------+
      ||                               ||
      ||                               ||
      ||                               ||
      ||   +------------------------+  ||
      +--> | Contents (Byte Stream) |<--+
           +------------------------+

前面3个相当于是ELF的元数据,用于告诉编译器/链接器/加载器定位索引各个section

注意:Segment和section的区别

  >> the segments contain information needed at runtime, while the sections contain information needed during linking

链接时,链接器会把多个.o的ELF文件中相同属性的section会合并到一个segment中,所以一个segment对应一个或多个sections

加载执行时,加载器会把一个Program Header指向的segment加载到运行时内存空间上 

 真正的代码数据这些运行时的内容是在各个section中,常见的section包括

 

注意: 对于不同的目标文件section可能会不同

比如只有可重定向目标文件才含有.rel.xx section用于告诉链接器需要对哪些符号进行解析重定向

只有可执行目标文件才有Program Header, 因为只有可执行目标文件才需要加载

程序编译链接的过程

为了深刻理解ELF,我们需要知道编译链接以及程序被加载执行的过程

我们平时写的源代码要想被目标机器执行,需要通过编译器链接器转成ELF文件

然后由加载器将ELF文件加载到内存中,最后CPU的PC才能执行到我们写的代码

编译器负责把源代码转换成机器指令以及相关的指令元数据按照ELF的格式生成可重定位目标文件

编译器负责把各个可重定向目标文件合并成最终的ELF格式的目标可执行文件

流程示意图如下

 

对外部引用的symbol,由于在本地找不到其定义,编译器会事先把地址留空并记录到即.rel.data/.rel.text这两个section里,

通过这种方式来告诉链接器将来需要对这些符号进行地址修正,所以链接器会遍历这两个section,试着去其他目标文件中找其定义

并根据merge好后的引用地址,对.re.xx里的所有REL_ENTRY进行地址关联,这就是链接器的符号决议

程序加载运行的过程

 加载器根据ELF的Program Header Table将PT_Type=PT_LOAD的segments Load到进程的虚拟地址空间

简单的说就是根据ELF文件将代码段,数据段,BSS段映射到内存中,然后CPU PC跳到入口处执行我们的程序

常用命令

readelf -h ELF_FILE        //查看ELF Header
readelf -l ELF_FILE        //查看Program Headers
readelf -S ELF_FILE        //查看section Headers
readelf -s ELF_FILE        //查看symtab里的所有symbol

nm ELF_FILE                 // List symbol from Object File
size ELF_FILE                //  查看各段大小

参考Appendix

    https://www.cnblogs.com/tsingke/p/9747141.html

    https://segmentfault.com/a/1190000016433829?utm_source=tag-newest

 

posted @ 2020-03-27 10:15  dengcai_xu_14  阅读(136)  评论(0)    收藏  举报