链接
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了链接相关的知识,希望对你有一定的参考价值。
一.几个重要的基本概念
链接:链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可以被加载到存储器中并执行。
编译器驱动程序:编译的过程可以分为以下几个步骤:1.语言预处理器 2.编译器 3.汇编器 4.链接器
静态链接:以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出。输入的可定位目标文件,包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标文件。
目标文件:1.可重定位目标文件 2.可执行目标文件 3.共享目标文件
可重定位目标文件:一个典型的ELF可重定位目标文件格式,
ELF |
.text |
.rodata |
.data |
.bbs |
.symtab |
.rel.text |
.debug |
.line |
.strtab |
节头部表 |
符号和符号表:
每个可重定位目标模块m都有一个模块表,它表示m所定义和引用的符号的信息,在链接的上下文中,有三种不同的符号:
1.由m定义并能被其他模块引用的全局符号2.由其他模块定义并能被模块m引用的全局符号 3.只能被模块m定义和引用的本地符号
二.重要的几个过程
静态库链接:
在符号解析的阶段,链接器从左到右按照它们在编译器驱动程序命令行上出现的相同顺序来扫描可重定位目标文件和存档文件。(驱动程序自动将命令行中所有的.c文件翻译成.o文件),在这次扫描中,链接器维持一个可重定位目标文件的集合E(这个集合中的文件会被合并起来形成可执行文件),一个未解析的符号(即引用了但是尚未定义的符号)集合U,以及一个在前面输入文件中已定义的符号集D,初始时,E、U和D都是空的。
重定位:
一旦链接器完成了符号解析这一步,它就把代码中的每一个符号引用和一个确定的符号定义(跟它的一个输入目标模块中的一个符号表条目)联系起来,在这时,链接器就知道它的输入目标模块中的代码节和数据节的确切大小,现在就可以开始重定位了,在这个步骤中,将合并输入模块,并为每个符号分配运行时地址。重定位包括两个步骤:1.重定位节和符号定义 2.重定义节中的符号引用
动态链接共享库:共享库是以两种不同方式来“共享”的,首先在任何给定的文件系统中,对于一个库只有一个.so文件,所有引用该库的可执行目标文件共享这个.so文件中的代码和数据,而不是像静态库的内容那样被拷贝和嵌入到引用它们的可执行文件中,其次,在存储器中,一个共享的.text节的一个副本可以被不同正在运行的进程共享。
从应用程序中加载和链接共享库:应用程序还有可能在它运行时要求动态链接器加载和链接任意共享库,而无需在编译时链接到那些库到应用中。
处理目标文件的一些工具:
AR:创建静态库,插入、删除、列出和提交成员
STRINGS:列出一个目标文件中所有可打印的字符串,
STRIP:从目标文件中删除符号表信息
NM:列出一个目标文件的符号表中定义的符号
SIZE:列出目标文件中的节的名字和大小
READELF:显出一个目标文件的完整结构,包括ELF头中的编码所有信息,包含SIZE和NM的功能
OBJDUMP:所有二进制工具之母,能够显示一个目标文件中所有的信息,它最大的作用是反汇编.text中的二进制指令。
三.小结
链接可以在编译时由静态编译器来完成,也可以在加载时和运行时由动态链接器来完成。链接器处理成为目标文件的二进制文件,它有三种不同的形式:可重定位的、可执行的和共享的。可重定位的目标文件由静态链接器合并成为一个可执行的目标文件,它可以加载到存储器中并执行。共享目标文件(共享库)是在运行时由动态链接器链接和加载的,或者隐含地在调用程序被加载和开始执行时,或者根据需要在程序调用dlopen库的函数时。链接器的两个主要任务是符号解析和重定位,符号解析将目标文件中的每个全局符号都绑定到一个唯一的定义,而重定位确定每个符号的最终存储地址,并修改对那些目标的引用。
以上是关于链接的主要内容,如果未能解决你的问题,请参考以下文章