深入理解计算机系统 第七章:链接

链接(static & dynamic)

具体实现方法见《深入理解计算机系统 第三版》 仅仅整理一些思路

静态连接

连接器的任务

  • 符号解析
  • 重定位:汇编器生成的代码和数据节都是从地址0开始,需要将每个符号定义与一个内存位置管理,从而重定位 这些节,并修改对这些符号的引用。

三种目标文件:

  • 可重定位目标文件:与其他可重定位目标文件结合,创建一个可执行文件
  • 可执行目标文件
  • 共享目标文件

可重定位文件格式

深入理解计算机系统 第七章:链接_第1张图片

部分说明:

.rodata 只读数据 .symtab 符号表

.rel.text 一个.text节的位置列表,组合时需要修改

.rel.data 被模块引用或定义的所有全局变量重定位信息

符号与符号表

符号表包含该文件(m)定义和引用的符号信息

  • m定义的呗其他模块引用的全局符号
  • 其他模块定义被m引用的全局符号
  • 只被m定义和引用的全局符号 带static的全局变量和函数

attention:不包含本地非静态的符号,这些在栈中管理

深入理解计算机系统 第七章:链接_第2张图片

section 用数值表示对应节 1对应.text节,其余同理

处理重定义的全局符号

未初始化—弱变量 初始化----强变量

  • 不允许有多个同名的强符号
  • 优先选择强符号
  • 如果多个弱符号同名任意选择一个

静态库连接

旧有技术缺点:

  • 每个可执行文件都包含着一份标准函数集合的副本,浪费空间。
  • 并且每个运行程序都会将这些函数放在内存中,浪费内存。
  • 如果标准函数一旦改变需要重新编译整个文件

静态库目的:

  • 将相关函数编译为独立的模块,封装成为单独的静态库文件
  • 链接时候,链接器只需要复制被引用的目标模块

重定位

STEP1:将所有的相同类型节合并为同一类型的聚合节

STEP2:修改代码节和数据节中对每个符号的引用,需要使用重定位条目

深入理解计算机系统 第七章:链接_第3张图片

两种基本重定位:

R_X86_64_PC32:32位PC地址相对引用

R_X86_64_32:32位绝对地址引用

可执行目标文件

相比于重定位目标文件少了.rel节 多了入口点 和.init段 其他相似

动态链接

静态缺点:

  • 定期维护或者更新后需要显式第将程序与库重新链接
  • 对于经常使用的函数如I/O,运行时这些代码会复制到运行进程的文本段,浪费内存

共享库(共享目标文件)是一个目标模块,在运行或者加载时候可以加载到任意的内存地址,并和一个在内存中的程序链接起来。这个过程为动态链接

Linux中的中有简单的接口来实现在运行时候来加载和链接共享库

共享库的一个主要目的是允许多个正在运行的进程共享内存中相同的代码,因此节约了内存资源。实现方式:位置无关代码

位置无关代码

原理:无论在内存中的何处加载一个目标模块,数据段与代码段的距离不变(即在运行时候,代码段中的任何指令和数据段中的任何变量的距离是一个常量),与绝对内存位置无关

实现方式GOT(全局偏移量表)+PLT过程链接表

深入理解计算机系统 第七章:链接_第4张图片
深入理解计算机系统 第七章:链接_第5张图片
深入理解计算机系统 第七章:链接_第6张图片

小结

连接器的两个主要任务:

  • 符号解析:将目标文件的每个全局符号绑定到一个唯一的定义
  • 重定位:确定每个符号的最终内存地址,修改对这些目标的引用。

程序中会引起错误的地方:

  • 全局变量重名
  • 连接器从左到右的顺序扫描来解析符号引用

使用动态链接,共享库的例程和数据可能仍然未解析,当第一次调用时候才会加载(LAZY模式,相对的有NOW模式)

共享库实现方法:位置无关代码

符号的最终内存地址,修改对这些目标的引用。

程序中会引起错误的地方:

  • 全局变量重名
  • 连接器从左到右的顺序扫描来解析符号引用

使用动态链接,共享库的例程和数据可能仍然未解析,当第一次调用时候才会加载(LAZY模式,相对的有NOW模式)

共享库实现方法:位置无关代码

你可能感兴趣的:(经验分享)