Linux内核分析——第七章 链接
第七章——链接
1、链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载到存储器并执行。
2、链接可以执行于编译时,加载时,运行时。
7.1编译器驱动程序
1、大多数编译系统提供编译驱动程序,它代表用户在需要时调用语言预处理器、编译器、汇编器和链接器。
7.2 静态链接
1、像Unix ld程序这样的静态链接器以一组可重定位目标文件和命令行参数作为输入,生成一个完全链接的可以加载运行的可执行目标文件作为输出。
2、输入的可重定位目标文件由各种不同的代码和数据节组成。
为了构造可执行文件,链接器必须完成两个主要任务:
(1)符号解析。目标文件定义和引用符号。符号解析的目的是将每个符号引用刚好和一个符号定义联系起来。
(2)重定位。编译器和汇编器生成从地址0开始的代码和数据节。
7.3 目标文件
1、目标文件有三种形式:
(1)可重定位目标文件;
(2)可执行目标文件;
(3)共享目标文件;
2、编译器和汇编器生成可重定位目标文件(包括共享目标文件)。链接器生成可执行目标文件
3、各个系统之间,目标文件格式都不相同。直到今天,可执行文件仍然被称为a.out文件。
7.4 可重定位目标文件
1、典型的ELF可重定位目标文件的格式
7.5符号和符号表
1、每个可重定位目标模块m都有一个符号表,它包含m所定义和引用的符号的信息。
2、在链接器的上下文中,有三种不同的符号:
(1)由m定义并能被其他模块引用的全局符号;
(2)由其他模块定义并被模块m引用的全局符号(外部符号);
(3)只被模块m定义和引用的本地符号;
7.6符号解析
1、链接器解析符号引用的方法是将每个引用与它输入的可重定位目标文件的符号表中的一个确定的符号定义联系起来。
7.6.1 链接器如何解析多重定义的全局符号
1、在编译时,编译器向汇编器输出每个全局符号,或者是强或者是弱,而汇编器把这个信息隐含的编码在可重定位目标文件的符号表里。
2、函数和已初始化的全局变量是强符号,未初始化的全局变量是弱符号。
3、根据强弱符号的定义,Unix链接器使用下面的规则来处理多重定义的符号:
规则1:不允许有多个强符号。
规则2:如果有一个强符号和多个弱符号,那么选择强符号。
规则3:如果有多个弱符号,那么从这些弱符号中任意选择一个。
7.6.2 与静态库链接
1、所有的编译系统都提供一种机制,将所有相关的目标模块打包成为一个单独的文件,称为静态库。当链接器构造一个输出的可执行文件时,它只拷贝静态库里被应用程序引用的目标模块。
2、在链接时,链接器将只拷贝程序引用的目标模块。
3、在Unix系统中,静态库以一种称为存档的特殊文件格式存放在磁盘中。
4、存档文件是一组连接起来的可重定位目标文件的集合。存档文件名由后缀.a标识。
5、链接时加上-static参数告诉编译器驱动程序,链接器应该构建一个完全链接的可执行目标文件,它可以加载到存储器并执行,在加载时无需更进一步的链接。
7.6.3 链接器如何使用静态库来解析引用
1、在符号解析的阶段,链接器从左到右按照他们在编译器驱动程序命令行上出现的相同的顺序来扫描可重定位目标文件和存档文件。(驱动程序自动将命令行中所有的.c文件翻译为.o文件)
2、在这次扫描中,链接器维持一个可重定位目标文件的集合E(这个集合中的文件会被合并起来形成可执行文件),一个未解析的符号(即引用了但是尚未定义的符号)集合U,以及一个在前面输入文件中已定义的符号集合D。初始时,E、U和D都是空的。
7.7 重定位
1、重定位由两步组成:
(1)重定位节和符号定义
(2)重定位节中的符号引用
2、无论何时汇编器遇到对最终位置未知的目标引用,它就会生成一个重定位条目,告诉链接器在将目标文件合并成可执行文件时如何修改这个引用。
3、代码的重定位条目放在.rel.text中,已初始化数据的重定位条目放在.rel.data中。
4、PC值通常是存储器中下一条指令的地址。
7.8 可执行目标文件
1、C程序开始时是一组ASCII文本文件,已经被转化为一个二进制文件,且这个二进制文件包含加载程序到存储器并运行它所需的所有信息。
2、典型的ELF可执行文件中的各类信息:
3、可执行目标文件的格式类似于可重定位目标文件的格式。ELF头部描述文件的总体格式。它还包括程序的入口点,也就是当程序运行时要执行的第一条指令的地址。
7.9 加载可执行目标文件
1、加载器将可执行目标文件中的代码和数据从磁盘拷贝到存储器中,然后通过跳转到程序的第一条指令入口点来运行该程序。这个将程序拷贝到存储器并运行的过程叫做加载。
2、在32位Linux系统中,代码段总是从地址0x08048000处开始。
3、数据段是在接下来的下一个4KB对齐的地址处。运行时堆在读/写段之后接下来的第一个4KB对齐的地址处,并通过调用malloc库往上增长。
4、还有一个段是为共享库保留的。
5、用户栈总是最大的合法用户地址开始,向下增长的(向低存储器地址方向增长)。从栈的上部开始的段是为操作系统驻留存储器的部分(内核)的代码和数据保留的。
7.10 动态链接共享库
1、静态库和所有的软件一样,需要定期维护和更新。
2、共享库是致力于解决静态库缺陷的一个现代创新产物。
3、共享库是一个目标,在运行时,可以加载到任意的存储器地址,并和一个在存储器中的程序链接起来。这个过程称为动态链接,是由一个叫做动态链接器(dynamic linker)的程序来执行的。
4、共享库也称为共享目标,在Unix系统中通常用.so后缀来表示,微软的操作系统大量的利用了共享库,它们称为DLL(动态链接库)。
5、共享库是以两种不同的方式来“共享”的。首先,在任何给定的文件系统中,对于一个库只有一个.so文件。所有引用该库的可执行目标文件共享这个.so文件中的代码和数据,而不是像静态库的内容那样被拷贝和嵌入到引用它们的可执行的文件中。其次,在存储器中,一个共享库的.text节的一个副本可以被不同的正在运行的进程共享。
(1)一种共享方式就是隐式链接,基本的思路:当创建可执行文件时,静态执行一些链接,然后在程序加载时,动态完成链接过程。
(2)一种共享方式就是“显式链接”,应用程序被加载时,动态链接器加载和链接共享库的情景。应用程序还可能在它运行时要求动态链接器加载和链接任意共享库,而无需在编译时链接那些库到应用中。
5、动态链接器通过执行下面的重定位完成链接任务:
(1) 重定位libc.so的文本和数据到某个存储器段。
(2) 重定位libvector.so的文本和数据到另一个存储器段。
(3) 重定位p2中所有对由libc.so和libvector.so定义的符号的引用。
7.11 从应用程序中加载和连接共享库
1、dlopen函数加载和链接共享库filename。
2、dlsym函数的输入是一个指向前面已经打开共享库的句柄和一个符号名字,如果该符号存在,就返回符号的地址,否则返回NULL。
3、如果没有其他共享库正在使用这个共享库,dlclose函数就卸载该共享库。
4、dlerror函数返回一个字符串,它描述的是调用dlopen、dlsym或者dlclose函数时发生的最近的错误,如果没有错误发生,就返回NULL。
7.12 与位置无关的代码(PIC)
1、共享库的一个主要目的就是允许多个正在运行的进程共享存储器中相同的库代码,因而节约宝贵的存储器资源。
2、不需要链接器修改库代码就可以在任何地址加载和执行这些代码。这样的代码叫做与位置无关的代码(PIC)。
3、ELF编译系统使用一种有趣的技术,叫做延迟绑定,将过程地址的绑定推迟到第一次调用该过程时。
4、延迟绑定是通过两个数据结构之间简洁但又有些复杂的交互来实现的,这两个数据结构是:GOT和过程链接表(PLT)。GOT是.data节的一部分,PLT是.text节的一部分。
7.13 处理目标文件的工具
1、在Unix系统中有大量可用的工具可以帮助理解和处理目标文件。
AR:创建静态库,插入、删除、列出和提取成员。
STRINGS:列出一个目标文件中所有可打印的字符串。
STRIP:从目标文件中删除符号的信息。
NM:列出一个目标文件的符号表中定义的符号。
SIZE:目标文件中节的名字和大小。
READELF:显示一个目标文件的完整结构,包括ELF头中的编码的所有信息。包含SIZE和NM的功能。
OBJDUMP:所有二进制工具之母,能够显示一个目标文件中所有的信息。它最大的作用是反汇编.text节中的二进制指令。
LDD:列出一个可执行文件在运行时所需要的共享库。
7.14 小结
1、链接可以在编译时由静态编译器来完成,也可以在加载时和运行时由动态链接器来完成。
2、链接器处理称为目标文件的二进制文件,它有三种不同的形式:可重定位的、可执行的和共享的。
3、链接器的两个主要任务是符号解析和重定位。
4、静态链接器是由像GCC这样的编译驱动器调用的。
5、多个目标文件可以被连接到一个单独的静态库中。
6、加载器将可执行文件的内容映射到存储器,并运行这个程序。
7、被编译为位置无关代码的共享库可以加载到任何地方,也可以在运行时被多个进程共享。
转载于:https://www.cnblogs.com/20135235my/p/5372229.html
Linux内核分析——第七章 链接相关推荐
- Linux内核分析 第七周 可执行程序的装载
张嘉琪 原创作品转载请注明出处 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 Linux内核分析 第七 ...
- Linux内核分析 笔记七 可执行程序的装载 ——by王玥
一.预处理.编译.链接和目标文件的格式 (一)可执行程序是怎么得来的? 1. 2.可执行文件的创建--预处理.编译和链接 shiyanlou:~/ $ cd Code ...
- Linux内核探讨-- 第七章
本文是个人分析<Linux内核设计与实现>而写的总结,欢迎转载,请注明出处: http://blog.csdn.net/dlutbrucezhang/article/details/136 ...
- Linux内核分析——第五章 系统调用
第五章 系统调用 5.1 与内核通信 1.系统调用在用户空间进程和硬件设备之间添加了一个中间层,该层主要作用有三个: (1)为用户空间提供了一种硬件的抽象接口 (2)系统调用保证了系统的稳定和安全 ( ...
- Linux内核分析(七)系统调用execve处理过程
本文的内容包括: 1. 用execve系统调用加载和执行一个可执行程序的代码演示 2. 用gdb跟踪系统调用execve的执行过程 3. execve系统调用处理过程分析 一.如何用execve系统调 ...
- Linux内核分析 - 网络[七]:NetFilter
内核版本:2.6.34 NetFilter在2.4.x内核中引入,成为linux平台下进行网络应用的主要扩展,不仅包括防火墙的实现,还包括报文的处理(如报文加密.报文分类统计等)等. NetFilte ...
- [网易云课堂]Linux内核分析(九)—— 课程总结
付何山+原创作品转载请注明出处+<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000; 导读:本文分为两个部分 ...
- Linux内核分析 读书笔记 (第七章)
第七章 链接 1.链接是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储器并执行. 2.链接可以执行于编译时,也就是在源代码被翻译成机器代码时:也可以执行于 ...
- 第七周linux内核分析
可执行程序的装载 作者 黎静+ 原创作品转载请注明出处 + <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-100002900 ...
- Linux与云计算——第二阶段Linux服务器架设 第七章:网站WEB服务器架设—日志分析平台...
Linux与云计算--第二阶段Linux服务器架设 第七章:网站WEB服务器架设-日志分析平台 日志分析:AWstats 安装AWstats分析http日志信息. [1] Install AWstat ...
最新文章
- Generation Language GL
- 手机webapp meta标签 (全屏)
- python可以做什么有趣的东西-python能做哪些生活有趣的事情
- .NET独有的精巧泛型设计模式
- S5PV210开发 -- 前言
- 【Coursera】SecondWeek(2)
- cheatengine找不到数值_“不会找问题”,只配在底层,最高效的思维方式导图,人生开挂!...
- java接口开发_如果你想学好Java,这些你需要了解
- aws数据库同步区别_了解如何通过使用AWS AppSync构建具有实时数据同步的应用程序
- 1007 素数对猜想 (20分)
- iOS开发 autoResizingMask使用
- android4.2 音频模块启动分析,Android 音频模块学习小结
- Docker-compose部署gitlab中文版
- Python pygame 坦克大战
- python中char是什么_python有char类型吗
- 微信群发消息无限制解决方案
- 关于比尔盖茨的几点思考
- 网络基础之基于距离矢量的动态路由(RIP)
- 花 1 小时,开源设计 LoRa 继电器开关
- 实验四、 触发器的逻辑功能和应用
热门文章
- GraphQL 技术浅析
- Android String占位符功能
- iOS,Core Graphics
- 从 LinkedIn 的数据处理机制学习数据架构
- WPF学习(一)--布局控件简介
- Silverlight入门
- JAVA OOP(一)——OOP概念,类与对象
- 应用商店打开服务器错误,教你应用商店出现错误的修复方法
- linux 常用图形库,在Linux下常用的3款Git图形客户端
- 基于vc的freetype字体轮廓解析_才一年,长安又换新LOGO,连带字体也升级了,你喜欢吗?_搜狐汽车...