程序员的自我修养 | 目标文件

第三章-目标文件

编译器编译源代码后生成的文件叫做目标文件,格式上来说,它是已经编译后的可执行文件格式,只是还没有经过链接过程。

总结

在Linux中目标文件是ELF格式的,其中,除了文件头还有很多段,比如数据段、代码段

目标文件的格式

目标文件在Linux中是ELF格式(Executable Linkable Format),除此之外还有很多ELF格式的文件

  • 可重定位文件

    • Linux的 .o
    • 这类文件包含了代码和数据,可以被用来链接成可执行文件或共享目标文件
    • 静态链接库
  • 可执行文件

    • /bin/bash 下的文件,可以直接执行
  • 共享目标文件

    • Linux 的 .so

    Untitled

  • 核心转储文件

目标文件的内容

Untitled

有不同的段

  • 文件头

    • 描述整个文件的属性
      • 是否可执行
      • 是静态链接还是动态链接
      • 入口地址
      • 目标硬件
      • 目标操作系统
      • 段表:文件中各个段的位置
  • 代码段(.code .text)

    • 编译后执行语句都编译成机器代码保存在.text段
    • 属于指令区域,只读
  • 数据段 (.data)

    • 已经初始化的全局变量和局部静态变量
    • 属于数据区域
  • bss段

    • 未初始化的全局变量和局部静态变量
    • 属于数据区域
    • 仅仅记录所需大小

    但事实上上述只是简化版的ELF结构,真正的结构如下图

Untitled

  • 数据和指令会被映射到两个虚拟存储区域
    • 数据可读可写,指令区域只读
    • CPU缓存是数据缓存和指令缓存分离,有利于提高程序的局部性
    • 如果同时运行多个改程序,由于指令都是一样的,内存中只需要保存一份该程序的指令副本

ELF文件的文件头

Untitled

段表

保存ELF文件中各种段的基本属性的结构。描述了各个段的段名、段长度、在文件中的偏移、读写权限等

Untitled

段表的结构是一个数组里面每个元素是一个结构体,数组的长度就是不同的段的个数。如图上图所示,这个目标文件中一共有11个段,其中第一个元素是无效的段描述符,因此一共有10个有效的段。每一个结构体长下图这样

Untitled

重定位表 .rel.text

链接器在处理目标文件时,需要对目标文件中某些部位进行重定位,即代码段和数据段中那些对绝对地址的引用的位置。这些重定位信息都记录在ELF文件的重定位表里面。对于每个需要重定位的代码段和数据段,都会有一个相应的重定位表

比如.rel.text表示对.text段的重定位表, .rel.data就是对.data段的重定位表

字符串表

.strtab.shstrtab 表示字符串表和段表字符串表

字符串表用来保存普通的字符串,比如符号的名字

段表字符串表用来保存段名字

符号表

记录了目标文件中用到的所有符号,有符号名和符号值,符号值就是地址。

  • 定义在本目标文件中的全局符号
  • 在本目标文件中引用的全局符号,但没有定义在本目标文件中(外部符号)
    • printf

上述两个最重要,因为链接过程就是要把全局符号黏在一起,下面三个对于其他目标文件是不可见的,在链接过程中无关紧要

  • 段名
  • 局部符号:局部变量的变量名
    • 对链接过程没有作用
  • 行号信息

一个具体的符号表例子

Untitled

Untitled

调试表

Untitled