深入理解计算机第七章

在第七章链接中,链接可以在编译时由经他编译器完成,也可以在加载时和运行时由动态链接器来完成。链接器处理可以为目标文件的二进制文件,它有三种不同的形式:可重定位和可执行和共享的。

链接器的两个主要的任务是符号解析和重定位,符号解析将文件中的每个全局符号都绑定到一个唯一的定义,而重新定位确定每个符号的最终存储器地址,修改对那些目标的引用。

静态链接是由像GCC这样的编译驱动器调用的。

多个目标文件可以被绒映射到存储器中,并运行这个程序。

加载器将可执行文件的内容映射到存储器,并运行这个程序。

被编译为位置无关代码的共享库可以加载到任何地方,也可以在运行时被多个进程共享。为了加载和链接和访问共享库的函数和数据,应用程序还可以在运行时使用动态的链接器。

1.编译器驱动程序

1.大部分编译系统提供编译驱动程序:代表用户在需要时调用语言预处理器、编译器、汇编器和链接器。

   (1)C预处理器:源程序main.c->ASCII码中间文件main.i

   (2)C编译器:main.i->ASCII码汇编语言文件main.s

   (3)C汇编器:main.s->可重定位目标文件

2.运行链接器程序ld,将各种.o文件以及必要的系统目标文件组合起来,创建可执行文件。

3.运行可执行文件:./可执行文件名字

4.外壳调用操作系统中加载器函数,拷贝可执行文件中的代码和数据到存储器,将控制转移到这个程序的开头

2.静态链接

1.以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载和运行的可执行目标文件作为输出。

2.输入的可重定位的目标文件由各种不同的代码和数据节组成。

3.指令在一个节中,初始化的全局变量在另一个节中,而未初始化的变量又在另外一个节中。

为了构造可执行文件,链接器必须完成两个主要任务:

-符号解析

目标文件定义和引用符号。符号解析的目的是将每个符号引用刚好和一个符号定义联系起来。

-重定位

编译器和汇编器生成从地址0开始的饿代码和数据节。链接器通过把每个符号定义与一个存储器位置联系起来,然后修改所有对这些符号的引用,使得它们指向这个存储器位置,从而重定位这些节。

3.目标文件

-编译器和汇编器生成可重定位目标文件(包括共享目标文件)。链接器生成可执行目标文件。从技术上来说,一个目标模块就是一个字节序列,而一个目标文件就是一个存放在磁盘文件中的目标模块。

-编译器和汇编器生成可重定义目标文件(包括共享目标文件)。链接器生成可执行目标文件。

目标文件三种形式:可重定位目标文件,可执行目标文件,共享目标文件。

目标文件格式:Linux——可执行可连接(ELF格式)

              Windows——可移植可执行格式(PE)

4.可重定位目标文件

 。ELF头(ELF header)以一个16字节的序列开始,这个序列描述了生成该文件的系统的字的大小和字节顺序。ELF头剩下的部分包含帮助链接器语法分析和解释目标文件的信息。其中包括ELF头的大小、目标文件的类型(如可重定位、可执行或是共享的)、机器类型(如IA32)、节头部表的文件偏移,以及节头部表中的条目大小和数量。不同的节的位置和大小是由节头部表描述的,其中目标文件中每个节都有一个固定大小的条目。

夹在ELF头和节头部表之间的都是借。一个典型的ELF可重定位目标文件包含下面几个节:

  • .text         已编译程序的机器代码
  • .rodata     只读数据
  • .data         已初始化的全局C变量。局部C变量在运行时保存在栈中,既不出现在.data节中 ,也不出现在.bss节中。
  • .bass        未初始化的全局C变量。在目标文件中这个节不占据实际的空间,它仅仅是一个占位符。目标文件格式区分初始化和未初始化变量是为了空间效率:在目标文件中,未初始化变量不需要占据任何实际的磁盘空间。
  • .symtab   一个符号表,它存放在程序中定义和引用的函数和全局变量的信息。每个可重定位目标文件在.symtab中都有一张符号表 。
  • .rel.text    一个.text节中位置的列表,当链接器吧这个目标文件和其他文件结合时,需要修改这些位置。一般而言,任何调用外部函数或引用全局变量的指令都需要修改。另一方面,调用本地函数的指令则不需要修改。注意,可执行目标文件中并不需要重定位信息,因此通常省略,除非用户显示第指示链接器包含这些信息。
  • .rel.data    被模块引用或定义的任何全局变量的重定位信息。一般而言,任何已初始化的全局变量,如果它的初始值是一个全局变量地址或者外部定义函数的地址,都需要被修改。
  • .debug      一个调试符号表,其条目是程序总定义的局部变量和类型定义,程序中定义和引用的 全局变量,以及原始的C源文件。
  • .line         原始C源文件中的行号和.text节中机器指令之间的映射。
  • .strtab     一个字符串表,其内容包括.symtab和.debug节中的符号表,以及节头部中的节名字。

5.符号和符号表

每个可重定位目标模块m都有一个符号表,包含m所定义和引用的符号的信息。

在链接器的上下文中,三种不同的符号:

1.有m定义并能被其他模块引用的全局符号。全局链接器对应于非静态的C函数以及被定义为Cstatic 属性的全局变量。

2.有其他模块定义并被模块m以引用的全局符号——外部符号,对应于定义在其他模块中的C函数和变量

3.只被模块m定义和引用的本地符号。

6.符号解析

根据强弱符号的定义,Unix链接器使用下面的规则来处理多重定义的符号:

  • 规则1:不允许有多个强符号。
  • 规则2:如果有一个强符号和多个弱符号,那么选择强符号。
  • 规则3:如果有多个弱符号,那么从这些弱符号中任意选择一个。

  在符号解析的阶段,链接器从左到右按照它们在编译器驱动程序命令行上出现的相同顺序来扫描可重定位目标文件和存档文件。在这次扫描中,链接器维持一个可重定位目标文件的集合E(这个集合中的文件会被合并起来形成可执行文件),一个未解析的符号(即引用了但是尚未定义的符号)集合U,以及一个在前面输入文件中已定义的符号集合D。初始时,E、U和D都是空的。

7.重定位

重定位有两步组成:

1.重定位节和符号定义。在这一步中,链接器将所有相同类型的节合并为同一类型的新的聚合节。然后,链接器将运行时存储器地址赋给新的聚合节,赋给输入模块定义的每个节,以及赋给输入模块定义的每个符号。当这一步完成时,程序中的每个指令和全局变量都有唯一的运行时存储器地址了。

2.重定位节中的符号引用。在这一步中,链接器修改代码节和数据节中对每个符号的引用,使得它们指向正确的运行时地址。为了执行这一步,链接器依赖于称为重定位条目的可重定位目标模块中的数据结构。

8.可执行目标文件

  可执行目标文件的格式类似于可重定位目标文件的格式。ELF头部描述文件的总体格式。它还包括程序的入口点,也就是当程序运行时要执行的第一条指令的地址。.text 、.rodata和.data 节和可重定位目标文件中的节是相似的,除了这些节已经被重定位到它们最终的运行时存储器地址以外。.init节定义了一个小函数,叫做_init,程序的初始化代码会调用它。

9.加载可执行目标文件

  每个Unix程序都有一个运行时存储器映像。例如:在32位Linux系统中,代码段总是从地址(0x8048000)处开始。数据段是在接下来的下一个4KB对齐的地址处。运行时堆在读/写段之后接下来的第一个4KB对齐的地址处,并童工调用malloc库往上增长。还有一个段是为共享库保留的。用户栈总是从最大的合法用户地址开始,向下增长的(向低存储器地方向增长)。从栈的上部开始的段是为操作系统驻留存储器的部分(也就是内核)的代码和数据保留的。

10.动态链接共享库

  共享库是致力与解决静态库缺陷的一个现代创新产物。共享库是一个目标模块,在运行时,可以加载到任意的存储器地址,并加一个在存储器中的程序链接起来。这个过程称为动态链接,是由一个叫做动态链接器的程序来执行的。共享库也称为共享目标,在Unix系统中通常用.so后缀来表示。

11.从应用程序中加载和链接共享库

动态链接在现实中的例子:

-分发软件

-构建高性能Web服务器

12.与位置无关的代码(PIC)

PIC数据引用

PIC函数调用

时间: 2024-11-05 22:46:50

深入理解计算机第七章的相关文章

深入理解JVM 第七章 虚拟机类加载机制

Java虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的加载机制. 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括了:加载(Loading).验证(Verification).准备(Preparation).解析(Resolution).初始化(Initialization).使用(using).和卸载(Unloading)七个阶段.其中验证.准备和解析三个部分统称为连接(Link

《深入理解计算机系统》第七章 链接 读书笔记

第七章链接 链接:将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载.连接可执行于编译时.加载时.运行时.由叫链接器的程序执行. 链接器使得分离编译成为可能.使得可以把 大程序分解成小模块,利于管理. 理解链接器将帮助你构筑大程型序:避免一些危险的编程错误:帮助你理解语言的作用域规则是如何实现的:帮助你理解其他重要的系统概念:使你能够利用共享库. 7.1 编译器驱动程序 驱动程序的工作:1.运行C预处理器,将C源程序(.c)翻译成一个ASCⅡ码中间文件(.i):2.运行C

《深入理解计算机系统》读书笔记第七章——链接

<深入理解计算机系统>第七章 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或拷贝)到存储器并执行. 链接的时机 编译时,也就是在源代码被翻译成机器代码时 加载时,也就是在程序被加载器加载到存储器并执行时. 运行时,由应用程序执行. 在现代系统中,链接是由链接器自动执行的. 7.1 编译器驱动程序 编译系统提供编译驱动程序——调用语言预处理器.编译器.汇编器和链接器. (1)运行C预处理器:源程序main.c->ASCII码中间文件main.i (2)

《深入理解计算机系统》第七章学习笔记(初稿)

第七章 链接 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或拷贝)到存储器并执行.链接可以执行于编译时,也就是在源代码被翻译成机器代码时:也可以执行于加载时,也就是在程序被加载器加载到存储器并执行时:甚至执行于运行时,由应用程序来执行.在早期的计算机系统中,链接是手动执行的.在现代系统中,链接是由叫链接器的自动执行的. 理解链接器将帮助构造大型程序 理解链接器将帮助避免一些危险的编程错误 理解链接器将帮助语言的作用域规则是如何实现的 理解链接器将帮助其他重要

第七章读书笔记《深入理解计算机系统》

第七章 读书笔记<深入理解计算机系统> 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或拷贝)到存储器并执行. 链接可以执行于编译时,也就是在源代码被翻译成机器代码时:也可以执行于加载时,也就是在程序被加载器加载到存储器并执行时:甚至执行于运行时,由应用程序来执行. 在早期的计算机系统中,链接是手动执行的.在现代系统中,链接是由叫链接器的自动执行的. 7.1 编译器驱动程序 1.大部分编译系统提供编译驱动程序:代表用户在需要时调用语言预处理器.编译器.汇编器

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

<深入理解计算机系统>第七章 链接 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(货被拷贝)到存储器并执行. 链接的时机 编译时,也就是在源代码被翻译成机器代码时 加载时,也就是在程序被加载器加载到存储器并执行时 运行时,由应用程序执行 链接器使分离编译称为可能. 链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或拷贝)到存储器并执行. 链接可以执行于编译时,也就是在源代码被翻译成机器代码时:也可以执行于加载时,也就是在程序

转自邓凡平 《深入理解Android:Wi-Fi,NFC和GPS》章节连载[节选]--第七章 深入理解Wi-Fi P2P部分节选

本章主要内容: 介绍Wi-Fi P2P相关知识: 介绍Android中WifiP2pService.wpa_supplicant的相关代码. 7.1  概述 承接第6章介绍的WSC,本章将继续介绍Wi-Fi Alliance(Wi-Fi联盟)推出的另外一项重要技术规范Wi-Fi P2P.该规范的商品名为Wi-Fi Direct,它支持多个Wi-Fi设备在没有AP的情况下相互连接. 在Android平台的Wi-Fi相关模块中,P2P的功能点主要集中在: Android Framework中的Wif

2014年计算机软考《网络管理》知识点-【第七章】

51CTO学院,在软考备考季特别整理了"2014年计算机软考<网络管理>知识点",帮助各位学院顺利过关!更多软件水平考试辅导及试题,请关注51CTO学院-软考分类吧! 查看汇总:2014年计算机软考<网络管理>知识点汇总  第七章 局域网互联 ☆局域网互连是将多个局域网相互联连接以实现信息交换和资源共享 7.1网络互连需求 7.1.1 局域网互连需求 (1) 局域网有以下三个限制因素 A. 局域网覆盖的距离是有限的; B. 局域网能支持的联网计算机的数目是有限的

《深入理解计算机系统》读书笔记 第七章 链接

第七章链接 链接(linking)是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储并执行. 链接的时机 编译时,也就是在源代码被翻译成机器代码时 加载时,也就是在程序被加载器加载到存储器并执行时. 运行时,由应用程序执行. 在现代系统中,链接是由链接器自动执行的. 链接器的关键角色:使分离编译称为可能. 7.1 编译器驱动程序 驱动程序的工作:1.运行C预处理器,将C源程序(.c)翻译成一个ASCⅡ码中间文件(.i):2.运行C编译器,将.i文件翻译