首先说说我为什么要去读这一章。这个学期开OS的课,在Morden Operating System上读到和Process有关的内容时看到这样一句话:“Process is fundamentally a container that holds all the information needed to run a program.”当时瞬间就想到了之前在csapp上看的模棱两可的“目标可执行文件”这个概念,于是重新又把它的第7章给读了一遍。


  要理解linker的作用,首先要搞明白他在整个计算机系统中处于一个什么样的位置。

  关于一个程序是怎样从码农们手撕的代码变成内存中能跑起来的程序这个过程就不再过多的叙述,这篇文章只是着重的去讲一下有关linker的这一部分。我们可以看到,linker的接受的输入是若干个.o文件,简单的说就是经过汇编器编译后生成的机器码,学名叫“relocatable object file(可重定位的目标文件)”,概念相近的称呼也有“module(模块)”。而汇编器的输出,是一个名叫“executable object program(目标可执行文件)”的二进制文件,这个文件的特征就是可以直接拷贝到内存中不需做任何的更改便可以运行。那么我们研究linker的作用是什么就可以从这里入手——为了构造最终的目标可执行文件,他需要对输入若干可重定位的目标文件做哪些事情?

  linker的作用主要有两个:

  (1)符号解析(symbol resolution):将每个符号的定义和每个符号的引用联系起来。(就是让系统明白,当这个程序run的时候,遇到的具体的变量或函数名,他们到底来自哪个文件的定义?是自己这个?还是其他一起输入linker的文件?)

  (2)重定位(relocation):把每个符号定义与存储器中的一个具体位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器的位置,从而重定位这些节。(在取得了每个符号的引用和定义的连接之后,要把符号的定义在存储器中绑定一个具体的地址)

  书中对符号的解释不是太清楚,至少我一开始的时候没太理解这个概念,在这儿结合书本的内容我用自己的话来概括下我对这个概念的理解。“符号”可以分为3类:

  1、由该模块定义的并且能被其他模块引用的“全局符号”。这里的“全局符号”对应于C语言中的非静态的函数和全局变量。

  2、由其他模块定义的由该模块引用的“全局符号”。解释同上

  3、由该模块定义的并且不能被其他模块引用的“全局符号”。对应于C语言中的静态变量,即static变量。static关键字相当于C语言中的“private”,即只能被自己这个文件(模块)使用的全局变量

  应当注意的是这里的变量全是全局变量而不是函数内部的私有变量,私有变量由运行时stack存储管理,linker对她并不感兴趣:)


  那么在了解了符号的概念之后,要想具体的了解linker对可重定位的目标可执行文件做的一些事情,就要了解relocatable object file的一些结构(他是怎么记录自身的各种符号信息的?)对不对?

  大家第一次看到这个图不要害怕,其实这就是汇编器(Assembler)将编译器处理的源代码文件进行进一步的编译或者说汇编之后形成的可重定位的目标可执行文件。这个文件的一个个小格子就是一个个的“节(section)”,他们存放该program的各种信息,在这里我只会解释几个我认为对理解linker作用很有必要的section。

.text:已编译程序的机器代码。

.data:已初始化的全局C变量。

.bss:未初始化的全局C变量。在这里符号只是一个占位符,它不占用任何的内存空间。

.symtab:一个符号表,存放在程序中定义和引用的函数和全部全局变量的信息。

.rel.test:存放代码的重定位条目(relocation entry)。

.rel.data:存放数据的重定位条目。


  以上都属于本章的基础知识铺垫部分,理解了上述内容,就可以很容易的理解linker对可重定位的目标可执行文件所做的操作了。

1、符号解析

  linker解析符号的方法是将每个符号的引用与所有输入的relocatable object file中的.symtab节中所有的符号定义中确定的一个联系起来。

 1.1链接器如何解释多重定义的全局符号?

  对于定义和引用都在一个module中的符号,linker的操作很简单,不需要指来指去改来改去;而真正要深入探讨的操作是对定义和引用不在同一个文件中的符号,尤其是当寻找到的符号定义有重名时。对此linker的做法是:

  (1)定义强符号和弱符号的概念。函数和已初始化的变量是强符号,为初始化的变量是弱符号。

  (2)设定规则。当有多重定义冲突的时候,linker遵循的规则是:

    one:不允许有多个强符号定义

    two:如果有一个强符号和多个弱符号定义,那么选择强符号定义

    three:如果有多个弱符号定义,那么随便选择一个

 1.2与静态库链接

  为什么会有“静态库”(static libraries)这个概念?

  首先在C语言编程中,我们需要实现丰富的功能,就要使用各种各样的函数接口。以ANSI C为例,它定义了一组广泛的标准I/O、字符串操作和整数数学函数,例如atoi、printf、scanf、strcpy、rand。他们在libc.a库中,对每个C程序来说都是可用的。如果不使用静态库,我们看看编程开发人员可以用什么其他的办法来向用户提供这些函数。

  一种实现的方法是让编译器直接辨认出对函数的调用,并直接生成相应的代码——这显然是不可行的,C语言中有大量的函数,这样做显然会使得编译器的设计变得相当复杂,每次添加、修改、删除一个函数时,都需要一个新的编译器版本。虽然对于编程人员而言这样是十分方便的,因为所有的标准函数都是直接可用的。

  另一种实现的方法是将所有的这些函数放到一个单独的可重定位的目标可执行文件中,它的优点是将编译器的设计与标准函数的实现分离开来,在一定程度上仍然便利编程人员。但是这样做的缺点却是每次运行程序的时候都要将该装载函数的rof文件copy到内存中去,而这样是很浪费内存空间的。而且同样将这么一大批函数赛到一个文件中,每次的维护都要重现编译整个源文件,这又是相当大的一个工作量。

  何为静态库?

  在Unix中,静态库以archive这种特殊的文件格式存在于磁盘中,是一组连接起来的relocatable object file的集合。

  

 1.3链接器如何使用静态库来解析引用

  维护一个基于(U,E,D)三个集合的算法


2、重定位

  在这个过程中,将合并模块并为每个符号分配运行时的地址。重定位由两个步骤组成:

  在这里有一个需要理解的概念是重定位条目(relocation entry)。在汇编器生成一个可重定位的目标模块时,当遇到UNDEFINED的符号,即不知道该数据或代码最终该存放到存储器的什么位置时,它就会为该符号生成一个重定位条目,即之前介绍的可重定位目标文件中的.rel.text和.rel.data两个表所记录的内容。

转载于:https://www.cnblogs.com/immortal-worm/p/5819036.html

链接器(linker)的作用——CSAPP第7章读书笔记相关推荐

  1. 三、C++ 链接器 linker

    cilinking:从C++源码到可执行二进制的过程.compile文件之后进行链接,找到每个符号.函数的位置,并将其链接在一起 每个文件被编译成一个独立的.obj文件作为translation un ...

  2. 链接器 --- Linker

    链接器 1. 背景 ​ 对于经常使用 IDE 的开发者,通常点击一个按钮就万事大吉了,这虽然极大简化了过程,但是对于我们C语言这些相对底层的开发者来说非常非常不友好,屏蔽了大量细节,不了解内部细节是非 ...

  3. C++ 学习之旅(2)——链接器Linker

    每一个.cpp文件经过编译之后都会生成对应的.obj文件,然后通过链接器把它们进行链接,最后就可以生成.exe可执行文件了. 在链接过程中,最常见的错误应该是重复定义了,如下例: Log.h void ...

  4. CSAPP第一章读书笔记

    本章从简单的hello,world程序讲起,讲解了系统为了执行该程序时,系统发生了什么以及为什么会这样 #include <stdio.h>int main(){printf(" ...

  5. C++链接器linker

    linking是从c++源码到二进制可执行文件的一个过程. 我们编译后会通过一个叫做链接的过程,链接的主要工作是找到每个符号和符号的位置并把它们链接在一起. 我们需要一种方法将这些文件链接到一个程序. ...

  6. s32ds 路径_S32DS 使用 tips--工程属性配置(编译选项和C编译器、汇编器及链接器设置)...

    内容提要 引言 1. 如何打开S32DS应用工程的属性设置 2. 设置Cross Settings 2.1 配置Create flash image 2.2 配置print size 3. 配置Tar ...

  7. arm-gcc链接器和链接脚本

    本文主要介绍了链接器和链接脚本的基本内容.主要偏向于入门级以及常见容易混淆的知识点. 1. 链接器介绍 在现在软件工程中,程序一般都比较复杂,通常由多个源文件组成.在编译的过程中会对这些源文件进行汇编 ...

  8. 链接器、链接过程及相关概念解析

    文章目录 1. 编译器驱动程序 2. 目标文件 2.1 可重定位目标文件(.o) 2.2 可执行目标文件(无后缀) 2.3 共享目标文件(.dll和.so) 3. 链接器的任务 3.1 符号解析(sy ...

  9. Linux调试私房菜(四)揭开链接器的面纱、汇编语言的内嵌编程

    七.揭开链接器的面纱(上) 1. 问题 源文件被编译后生成目标文件,这些目标文件如何生存最终的可执行程序? 2. 链接器的意义 链接器的主要作用是把各个模块之间相互引用的部分处理好,使得各个模块之间能 ...

最新文章

  1. RMAN Backups
  2. 叱咤风云的BERT为何败于商业环境?
  3. Eclipse 报 “Exception in thread main java.lang.OutOfMemoryError: Java heap space ”错误的解决办法
  4. python怎么清理垃圾_Python 中的“垃圾”是怎么回收的?
  5. 利用Android Studio快速搭建App
  6. java年月日时分秒格式_Java 日期时间 LocalDate LocalTime LocalDateTime类
  7. POJ2352 Stars
  8. Xgboost算法——Kaggle案例
  9. jQuery源码分析系列(35) : Ajax - jsonp的实现与原理
  10. 大数据Hadoop生态圈-组件介绍
  11. Android 系统源码中添加 androidx 依赖
  12. 使用JQuery快速高效制作网页交互特效第二章所有上机
  13. JanusGraph批量导入数据代码总结
  14. 好玩的Python库tqdm
  15. 电力电子转战数字IC——路科MCDF全览(持续更新)
  16. 全自动调节灯光强度的实现(仿真+程序+文档)
  17. Matlab三维离散点曲面拟合
  18. 常见的NoSQL数据库有哪些
  19. Webpack 4教程 - 第四部分,使用SplitChunksPlugin分离代码
  20. 整数n分解成素数乘积c语言,关于几种求素数的方法(C语言描述)

热门文章

  1. VC++ 显示对话框
  2. 图解在emu8086中学习几条汇编语言常用语句
  3. asp.net 表单总结
  4. iOS进阶_Socket(Socket简介代码演练)
  5. python slenium 中CSS定位
  6. SQL Server中的标识列
  7. key的数据类型是字符串
  8. ubuntu安装搜狗输入法的相关问题
  9. Storm具体的解释(二)、成为第一Storm申请书
  10. MemoryStream的一些问题