ELF、编译、链接、装载和库

2015/09/05 - C/C++

ELF文件分类

  1. 可重定位文件(Relocatable File) 与其他目标文件链接来创建可执行文件或者共享目标文件的代码和数据。

  2. 可执行文件(Executable File) 此文件规定了exec()如何创建一个程序的进程映像。

  3. 共享目标文件(SharedObject File) 首先链接编辑器可以将它和其它可重定位文件和共享目标文件一起处理,生成另一个共享目标文件。其次,动态链接器可能将它与某个可执行文件以及其他共享目标一起组合,创建进程映像。

  4. 核心转储文件(CoreDump File) 包含进程意外终止时的地址空间内容及其他信息。

ELF文件内容

符号表:

记录目标文件中所有符号和地址。符号代表函数和变量,链接过程基于符号进行

符号的地址(nm)

  • 可执行文件中,符号的地址对应程序运行时变量或函数的虚拟地址。
  • 共享目标文件中,符号的地址对应程序运行时变量或函数的虚拟地址和装载地址的偏移
  • 可重定位目标文件中,符号地址是不确定的

符号的类别

  • 强符号:函数和初始化了的全局变量
  • 弱符号:未初始化的全局变量为弱符号。

符号的引用

  • 强引用:符号在链接成可执行文件时,必须被正确决议。
  • 弱引用:链接时可有可无的符号;有则引用,没有也不报错。

重定位表:

记录用于修改相应段的内容的信息。

重定位

  • 普通重定位:链接时候重定位。
  • 动态重定位:加载、运行时重定位,一般有程序启动时动态加载符号来重定位,和函数符号被调用时候动态加载。

为什么需要重定位

  • 使用外部变量和函数地址不确定,需要在链接时确定
  • 动态库需要生成地址无关代码,需要进行指令修正

程序编译

  • 预编译:处理宏定义、条件编译、头文件包含等
  • 编译:把预处理完的文件进行一系列的词法分析、语法分析、语义分析及优化后生产相应的汇编代码文件。
  • 汇编:将汇编代码转变成机器可以执行的指令。
  • 链接:将程序链接成可执行文件或动态库。

MakeFile编译相关参数

-g选项新添加的是调试信息),被相关调试工具(如gdb)使用,可以被strip掉。

-rdynamic选项新添加的是动态连接符号信息,用于动态连接功能,比如dlopen()系列函数、backtrace()系列函数使用,不能被strip掉,即强制strip将导致程序无法执行。-rdynamic选项不产生任何调试信息,因此在一般情况下,新增的附加信息比-g选项要少得多。

-C指定编译目录

.PHONY:

链接器的工作

空间与地址分配:

扫描输入的目标文件,搜索其中的符号定义和符号引用。计算出输出文件中每个段合并后的长度和位置,并建立映射关系。

符号解析与重定向:

A.符号解析,找出外部符号在哪定义。如果外部符号在一个静态库中定义,则直接将对应的定义代码复制到最终生成的目标文件中

B.符号重定位。编译器在生成目标文件时,通常使用从零开始的相对地址,而在链接过程中,链接器从一个指定的地址开始,根据输入目标文件的顺序,以段(segment)为单位将他们拼接起来。其中每个段可以包括很多哥节(section)。除了目标文件的拼装, 重定位过程中还完成了下面两个任务:一是生成最终的符号表,二是对代码段(.text)中的某些位置进行修改,要修改的位置由编译器生成的重定位表指出。

指定输出文件各个段虚拟地址、段的名字、段存放顺序等:

指定程序入口、动态链接器名字、是否静态链接程序等选项:

静态连接、动态连接

静态链接:

由链接器在链接时将库的内容加入到可执行程序中。发生在程序编译期间

优点:可执行文件能不依赖其他库运行。

缺点:生成的可执行文件太大,需要更多的系统资源,在装入内存时也会消耗更多的时间。

动态链接:

可执行文件装载时或运行时,由操作系统的装载程序加载库。发生在程序装载期间

优点:无需重新编译可更新程序,节省内存和磁盘空间。

缺点:可执行程序依赖分别存储的库文件才能正确执行。

程序的装载

Linux内核装载ELF过程简介

  1. bash调用fork创建进程,新的进程调用execve系统调用执行指定的ELF文件。
  2. 检测ELF可执行文件的有效性。
  3. 设置动态链接器路径。
  4. 根据ELF可执行程序头表进行映射。
  5. 初始化ELF进程环境
  6. 将系统调用的返回地址修改成ELF可执行文件的入口点。对于静态链接的ELF可执行文件,就是ELF文件头中的ENTRY所指地址;对于动态链接的ELF可执行文件,程序入口点是动态链接器。

动态库的查找过程

  1. 可执行文件中的.dynamic指定的路径。
  2. ld.so.conf文件中指定的目录。
  3. 环境变量LD_LIBRARY_PATH指定的目录。

动态加载库

运行时加载,让程序自己在运行时控制加载指定的模块,并且可在不需要该模块的时候卸载 相关API

dlopen打开动态库,将其加载到进程的地址空间

dlsym查找动态库中指定的符号

dlclose将加载的动态库卸载

dlerror判断对动态库的其他API操作是否成功。

辅助工具

  • ar:创建静态库。插入、删除、列出和提取成员。
  • strings:列出一个目标文件中所有可打印的字符串。
  • nm:列出一个目标文件中的符号表中定义的符号(有可能被strip掉)。
  • size: 列出目标文件中节的名字和大小。
  • readelf:显示一个目标文件的完整结构。
  • objdump:显示一个目标文件中所有的信息,反编译.text节。
  • ldd:列出一个可执行文件在运行时所需的共享库。
  • xxd:以十六进制打印文件的所有内容。
  • Ldd (ldconfig -p |grep mysql)

如果文章对您有帮助,欢迎扫描下方二维码赞助(一分也是爱噢),谢谢

Search

    一分也是爱噢 一分也是爱

    目录