1:链接概述

链接(linking)是将各种代码和数据部分收集起来并组合成为一个单一文件的过程,这个文件可被加载(或被拷贝)到存储并执行。

编译系统提供的调用预处理器、编译器、汇编器和链接器来构造目标文件的。

2. 静态链接

为了构造可执行文件,链接器的两个主要任务

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

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

符号解析:
和引用定义在相同模块的本地符号;编译器只允许每个模块中每个本地符号有一个定义对于全局符号的解析。
当编译器遇到一个不是在当前模块中定义的符号时,它会假设该符号是在某个模块中定义的,生成一个链接器符号表条目然后交给链接器处理;
如果在链接器的任何模块中都找不到这个被引用的符号,它就输出一条错误信息然后终止
对于多重定义的全局符号;
函数和已经初始化的全局变量是强符号,未初始化的全局变量是弱符号 规则:
不允许有多个强符号
如果有一个强符号和多个弱符号,那么选择强符号
如果有多个弱符号,那么从其中任选一个
重定位
重定位节和符号定义:链接器将所有相同类型的节合并为同一类型的新的聚合节
重定位节中的符号引用:链接器修改代码节和数据节中对每个符号的引用,使得它们指向正确的运行时的地址
重定位条目。

  

3. 目标文件

三种形式

可重定位目标文件:包含二进制代码和数据,其形式可以在编译时与其他可重定位目标文件合并起来,创建一个可执行目标件。 

可执行目标文件:包含二进制代码和数据,其形式可以被直接拷贝到存储器并执行。

共享目标文件:一种特殊类型的可重定位目标文件,可以在加载或者运行地被动态地加载到存储器并链接。

4. 可重定位目标文件

  • 一个典型的ELF可重定位目标文件的格式:

ELF文件已经是适应到某一种CPU体系结构的二进制兼容文件了。

默认的ELF头加载地址是0x8048000,头部大概要到0x48100处或者0x483000处,也就是可执行文件加载到内存之后

5. 符号和符号表

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

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

 由m定义并能被其他模块引用的全局符号。
由其他模块定义并被模块m引用的全局符号。
只被模块m定义和引用的本地符号。

符号表

typedef struct{
int name; //字符串表中的字节偏移,指向符号的以NULL结尾的名字
int value; //符号的地址,对于可重定位的模块是距定义目标的节起始位置的偏移。
int size; //目标大小(单位:字节)
char type:4, //数据或函数
binding:4; //本地LOCAL/全局GLOBAL
char reserved;
char section; //到节头部表的索引
}Elf_Symbol;

每个符号都和目标的某个节相关联,由section字段表示。

  • ABS:不该被重定位的符号。
  • UNDEF:未定义的符号,在本目标模块中引用,但在其他地方定义。
  • COMMON:未被分配位置的未初始化数据目标。

6. 符号解析

与静态库链接

  • 所有的编译系统都提供一种机制,将所有相关的目标模块打包成为一个单独的文件,称为静态库(Linux下是存档文件,Windows下是lib),只拷贝静态库里被应用程序引用的目标模块。

  • 链接时加上-static参数告诉编译器驱动程序,链接器应该构建一个完全链接的可执行目标文件,它可以加载到存储器并执行,在加载时无需更进一步的链接。

如何处理多重定义的符号?
不允许有多个强符号
如果有一个强符号和多个弱符号,那么选择强符号
如果有多个弱符号,那么从这些弱符号中任意选择一个

  

7. 重定位

(1)重定位两步

重定位节和符号定义:链接器将所有相同类型的节合并为同一类型的新的聚合节
重定位节中的符号引用:
链接器修改代码节和数据节中对每个符号的引用,使得它们指向正确的运行时的地址重定位条目。
链接器依赖于称为重定位条目的可重定位目标模块中的数据结构。

(2)重定位条目

ELF定义了11种不同的重定位类型。两种最基本的重定位类型:

*R_386_PC32 重定位一个使用32位PC相对地址的引用。
*R_386_32 重定位一个使用32位绝对地址的引用。

(3)重定位符号引用

链接器修改代码节和数据节中对每个符号的引用,使得他们指向正确的运行时地址。

重定位PC相对引用
重定位绝对引用

8. 可执行目标文件及加载

(1)可执行目标文件

  • C程序开始时是一组ASCII文本文件,已经被转化为一个二进制文件,且这个二进制文件包含加载程序到存储器并运行它所需的所有信息。

  • 段头部表:可执行文件的连续片被映射到连续的存储器段,段头部表描述了这种关系。

  • 在32位Linux系统中,代码段总是从地址0x08048000处开始。

(2)加载可执行目标文件

加载器将可执行目标文件中的执行代码和数据从磁盘拷贝到存储器中,然后通过跳转到程序的第一条指令或入口点来运行该程序。这个将程序拷贝到存储器并运行的过程叫做加载。

要运行可执行目标文件p,可以在Unix外壳的命令行中输入它的名字:unix> ./p

将程序拷贝到存储器并运行的过程叫做加载。

用户栈总是最大的合法用户地址开始,向下增长的(向低存储器地址方向增长)。从栈的上部开始的段是为操作系统驻留存储器

的部分(内核)的代码和数据保留的。

9. 动态连接共享库

动态链接器通过执行下面的重定位完成链接任务:

  • 重定位libc.so的文本和数据到某个存储器段
  • 重定位libvector.so的文本和数据到另一个存储器段
  • 重定位p2中所有对libc.so和libvector.so定义的符号的引用
  • 最后动态链接器将控制传递给应用程序,此时共享库的位置已固定,并且在程序执行的过程中不会改变

(1)静态库的缺点

  • 首先,静态库在更新时,使用该库的程序需要与更新的库进行重新链接。
  • 其次,由于使用静态库的程序在链接时都会拷贝静态库里被应用程序引用的目标模块,像printf和scanf这样的函数的代码在运行时都会被复制到每个运行进程的文本段中,这造成了冗余,浪费了稀缺的存储器资源。

(2)共享库

共享库是一个目标模块,在运行时,可以加载到任意的存储器地址,并和一个在存储器中的程序链接起来。

这个过程称为动态链接,是由一个叫做动态链接器的程序来执行的。

共享库也称为共享目标,在Unix系统中通常用.so后缀来表示。微软的操作系统大量地利用了共享库,它们称为DLL(动态链接库)。

共享库是以两种不同的方式来“共享”的(在Windows中分别称为“隐式链接”和“显示链接”)。

         1:在任何给定的文件系统中,对于一个库只有一个.so文件。所有引用该库的可执行目标文件共享这个.so文件中的代码和数据,
而不是像静态库的内容那样被拷贝和嵌入引用它们的可执行的文件中。
2:在存储器中,一个共享库的.text节 一个副本可以被不同的正在运行的进程共享。

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

void *dlopen( const char *file, int mode );//将共享目标文件打开并且映射到内存中,并且返回句柄
void *dlsym( void *restrict handle, const char *restrict name );//回一个指向被请求入口点的指针
char *dlerror();//返回 NULL 或者一个指向描述最近错误的 ASCII 字符串的指针
char *dlclose( void *handle );//关闭句柄并且取消共享目标文件的映射

11. 处理目标文件的工具

AR:创建静态库,插入、删除、列出和提取成员。
STRINGS:列出一个目标文件中所有可打印的字符串。
STRIP:从目标文件中删除符号的信息。
NM:列出一个目标文件的符号表中定义的符号。
SIZE:目标文件中节的名字和大小。
READELF:显示一个目标文件的完整结构,包括ELF头中的编码的所有信息。包含SIZE和NM的功能。
OBJDUMP:所有二进制工具之母,能够显示一个目标文件中所有的信息。它最大的作用是反汇编.text节中的二进制指令。
LDD:列出一个可执行文件在运行时所需要的共享库。

  

Linux 第七章学习笔记的更多相关文章

  1. Linux 第五章 学习笔记

    ---恢复内容开始--- 第五章 系统调用 一.与内核通信 1.系统调用在用户控件进程和硬件设备之间添加了一个中间层. 为用户空间提供了一种硬件的抽象接口 系统调用保证了系统的稳定和安全 每个进程都运 ...

  2. linux第七章读书笔记

    Vim编辑器 Vim 仅仅通过键盘来在插入和执行命令等多种模式之间切换.这使得Vim可以不用进行菜单或者鼠标操作,并且最小化组合键的操作,对文字录入员或者程序员可以大大增强速度和效率. CHAPTER ...

  3. linux第三章学习笔记

    第三章 进程管理 进程是Unix操作系统抽象概念中最基本的一种. 进程管理是所有操作系统的心脏所在. 一.进程 1. 进程是处于执行期的程序.除了可执行程序代码,还包括打开的文件.挂起的信号.内核内部 ...

  4. 20135320赵瀚青LINUX第七周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周学习的内容主要是讨 ...

  5. Mudo C++网络库第七章学习笔记

    muduo编程示例 muduo库是设计来开发内网的网络程序, 它没有做任何安全方面的加强措施, 如果在公网上可能会受到攻击; muduo库把主动关闭连接这件事分成两步来做: 如果主动关闭连接, 会先关 ...

  6. 《Metasploit魔鬼训练营》第七章学习笔记

    P314 木马程序的制作 msfpayload和msfencoder已被msfvenom取代.使用msfvenom -h查看具体用法.以下网址也有相关教程: https://github.com/ra ...

  7. 《Linux内核设计与实现》第四章学习笔记

    <Linux内核设计与实现>第四章学习笔记           ——进程调度 姓名:王玮怡  学号:20135116 一.多任务 1.多任务操作系统的含义 多任务操作系统就是能同时并发地交 ...

  8. 《Linux内核设计与实现》第四章学习笔记——进程调度

                                                                        <Linux内核设计与实现>第四章学习笔记——进程调 ...

  9. 《Linux内核设计与实现》课本第五章学习笔记——20135203齐岳

    <Linux内核设计与实现>课本第五章学习笔记 By20135203齐岳 与内核通信 用户空间进程和硬件设备之间通过系统调用来交互,其主要作用有三个. 为用户空间提供了硬件的抽象接口. 保 ...

随机推荐

  1. windows下编写shell脚本执行错误

    在 windows 下,换行符是 \r\n,在linux下,换行符是 \n.如果你在IDEA里写sh脚本,可以手动设置脚本的换行符为 \n,如果你用notepad++写脚本,可以显示所有字符,以便明确 ...

  2. 超详细!Github团队协作教程(Gitkraken版)

    超详细!Github团队协作教程(Gitkraken版) 一.前期工作 1. 在 Github 上创建 organization step1. 登录Github网站,点击右上角头像,选择 " ...

  3. 【阿里八八】团队Alpha博客链接目录

    团队Alpha冲刺博客 阿里八八Alpha阶段Scrum(1/12) 阿里八八Alpha阶段Scrum(2/12) 阿里八八Alpha阶段Scrum(3/12) 阿里八八Alpha阶段Scrum(4/ ...

  4. Java设计模式之八 ----- 责任链模式和命令模式

    前言 在上一篇中我们学习了结构型模式的享元模式和代理模式.本篇则来学习下行为型模式的两个模式, 责任链模式(Chain of Responsibility Pattern)和命令模式(Command ...

  5. 「PKUSC2018」神仙的游戏

    题目链接 比如说上面\(|S|\)为12的字符串,我们欲求出\(f(9)\)的值,那么上面相同颜色的字符必须两两能够匹配.也就是说,同种颜色的字符集里不能同时出现0和1.如果只考虑同种颜色集里相邻的两 ...

  6. hashCode相关性能优化

    学习下hashMap中用到的关于hashCode性能优化技巧.作为笔记.为之后并发深入作基础. 1.关于提高性能的hash算法 在被模的位数为2的n次方时,用位与取代效率低下的模运算.位与效率相比模运 ...

  7. 20145236《网络攻防》Exp4 恶意代码分析

    20145236<网络攻防>Exp4 恶意代码分析 一.基础问题回答 如果在工作中怀疑一台主机上有恶意代码,但只是猜想,所有想监控下系统一天天的到底在干些什么.请设计下你想监控的操作有哪些 ...

  8. String.valueOf()方法注意

    String.valueOf();可以将 int char long float double boolean char[] 转化为字符串输出,但不是这几个类型时候,则会使用Object类型接收,底层 ...

  9. VsCode源码分析之布局

    关于VsCode源码编译运行,请参考这篇文章:VsCode源码编译运行 当然了,也可以参考官方文档(所以这里就不再赘述):https://github.com/Microsoft/vscode/wik ...

  10. docker安装jdk8

    1.下载jdk8 wget --no-cookies --no-check-certificate --header "Cookie: gpw_e24=http%3A%2F%2Fwww.or ...