动态链接相关知识

符号重定位

讲动态链接之前,得先说说符号重定位。

c/c++ 程序的编译是以文件为单位进行的,因此每个 c/cpp 文件也叫作一个编译单元(translation unit),
源文件先是被编译成一个个目标文件,
再由链接器把这些目标文件组合成一个可执行文件或库,链接的过程,其核心工作是解决模块间各种符号(变量,函数)相互引用的问题,对符号的引用本质是对其
在内存中具体地址的引用,因此确定符号地址是编译,链接,加载过程中一项不可缺少的工作,这就是所谓的符号重定位。本质上来说,符号重定位要解决的是当前编译单元如何访问「外部」符号这个问题。

因为编译是以源文件为单位进行的,编译器此时并没有一个全局的视野,因此对一个编译单元内的符号它是无力确定其最终地址的,而对于可执行文件来说,
在现代操作系统上,程序加载运行的地址是固定或可以预期的,因此在链接时,链接器可以直接计算分配该文件内各种段的绝对或相对地址。所以对于可执行文件来说,符号重定位是在链接时完成的(如果可执行文件引用了动态库里的函数,则情况稍有不同)。但对于动态链接库来说,因为动态库的加载是在运行时,且加载的地址不固定,因此没法事先确定该模块的起始地址,所以对动态库的符号重定位,只能推迟。

符号重定位既指在当前目标文件内进行重定位,也包括在不同目标文件,甚至不同模块间进行重定位,这里面有什么不同吗?如果是同一个目标文件内,或者
在同一个模块内,链接后,各个符号的相对地址就已经确定了,看起来似乎不用非得要知道最后的绝对地址才能引用这些符号,这说起来好像也有道理,但事实不是
这样,x86 上 mov
之类访问程序中数据段的指令,它要求操作数是绝对地址,而对于函数调用,虽然是以相对地址进行调用,但计算相对地址也只限于在当前目标文件内进行,跨目标
文件跨模块间的调用,编译期也是做不到的,只能等链接时或加载时才能进行相对地址的计算,因此重定位这个过程是不能缺少的,事实上目前来说,对于动态链接
即使是当前目标文件内,如果是全局非静态函数,那么它也是需要进行重定位的。

注:

动态链接,在可执行文件装载时或运行时,由操作系统的装载程序加载库。大多数操作系统将解析外部引用(比如库)作为加载过程的一部分。在这些系统上,可执行文件包含一个叫做import directory的表,该表的每一项包含一个库的名字。根据表中记录的名字,装载程序在硬盘上搜索需要的库,然后将其加载到内存中预先不确定的位置,之后根据加载库后确定的库的地址更新可执行程序。可执行程序根据更新后的库信息调用库中的函数或引用库中的数据。这种类型的动态加载成为装载时加载 ,被包括Windows和Linux的大多数系统采用。装载程序在加载应用软件时要完成的最复杂的工作之一就是加载时链接。

其他操作系统可能在运行时解析引用。在这些系统上,可执行程序调用操作系统API,将库的名字,函数在库中的编号和函数参数一同传递。操作系统负责立即解析然后代表应用调用合适的函数。这种动态链接叫做运行时链接 。因为每个调用都会有系统开销,运行时链接要慢得多,对应用的性能有负面影响。现代操作系统已经很少使用运行时链接。
  可以动态链接的库,在Windows上是dynamic link library (DLL),在UNIX或Linux上是Shared Library。库文件是预先编译链接好的可执行文件,存储在计算机的硬盘上。大多数情况下,同一时间多个应用可以使用一个库的同一份拷贝,操作系统不需要加载这个库的多个实例。
  动态链接的最大缺点是可执行程序依赖分别存储的库文件才能正确执行。如果库文件被删除了,移动了,重命名了或者被替换为不兼容的版本了,那么可执行程序就可能工作不正常。这就是常说的DLL-hell。

g++编译参数:

-shared 该选项指定生成动态连接库(让连接器生成T类型的导出符号表,有时候也生成弱连接W类型的导出符号),不用该标志外部程序无法连接。相当于一个可执行文件。

-fPIC:表示编译为位置独立的代码,不用此选项的话编译后的代码是位置相关的所以动态载入时是通过代码拷贝的方式来满足不同进程的需要,而不能达到真正代码段共享的目的。

-L.:表示要连接的库在当前目录中

-l Detour:编译器查找动态连接库时有隐含的命名规则,即在给出的名字前面加上lib,后面加上.so来确定库的名称

-I 项目中include包含的头文件寻找路径

时间: 2024-12-09 20:25:47

动态链接相关知识的相关文章

Linux动态库相关知识整理

动态库和静态库在C/C++开发中很常见,相比静态库直接被编译到可执行程序, 动态库运行时加载使得可执行程序的体积更小,更新动态库可以不用重新编译可执 行程序等诸多好处.作者是一个Linux后台开发,这些知识经常用到,所以 整理了一下这方面的知识.静态库相对简单,本文只关心Linux平台下的动态库. 创建动态库 这里我把一个短小却很有用的哈希函数编译成动态库做为示例,ELFhash用于对字符串做哈希,返回一个无符号整数. //elfhash.h #include <stdio.h> unsign

Linux 动态库相关知识整理

动态库和静态库在C/C++开发中很常见,相比静态库直接被编译到可执行程序,动态库运行时加载使得可执行程序的体积更小,更新动态库可以不用重新编译可执行程序等诸多好处.作者是一个Linux后台开发,这些知识经常用到,所以整理了一下这方面的知识.静态库相对简单,本文只关心Linux平台下的动态库. 创建动态库 这里我把一个短小却很有用的哈希函数编译成动态库做为示例,ELFhash用于对字符串做哈希,返回一个无符号整数. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 //elf

解析链接相关知识

在HTML中可能含有我们想要解析的链接的标签: <a> <frame> 样例: 1 <framesetcols="25%,75%"> 2 <frame src="frame_a.htm"> 3 <frame src="frame_b.htm"> 4 </frameset> <a href="url">Link text</a> 网站

动态链接详解

动态链接 动态链接的诞生: 动态链接产生最主要的原因就是静态链接空间浪费过于巨大,更重要的是现阶段各种软件都是模块化开发,不同模块都是由不同厂商开发的,一旦一个模块发生改变,整个软件就需要重新编译(静态链接的情况下). 动态链接主要思想: 把链接这个过程推迟到了运行时再运行,这就是动态链接(Dynamic Linking)的基本思想. 动态链接的好处: 1.动态链接将共享对象放置在内存中,不仅仅节省内存,它还可以减少物理页面的换进换出,也可以提高CPU缓存的命中率,因为不同进程间的数据与指令都集

实例分析ELF文件动态链接

参考文献: <ELF V1.2> <程序员的自我修养---链接.装载与库>第6章 可执行文件的装载与进程 第7章 动态链接 <Linux GOT与PLT> 开发平台: [[email protected] dynamic_link]# uname -a Linux tanghuimin 2.6.32-358.el6.x86_64 #1 SMP Fri Feb 22 00:31:26 UTC 2013 x86_64 x86_64 x86_64 GNU/Linux 实例讲解

了解动态链接(五)—— 动态符号表

动态符号表 (.dynsym) 用来保存与动态链接相关的导入导出符号,不包括模块内部的符号.而 .symtab 保存所有符号,包括 .dynsym 中的符号. 动态符号表中所包含的符号的符号名保存在动态符号字符串表 .dynstr 中. 使用 readelf 查看 .dynsym 表,如:readelf --dyn-syms libstdc++.so. 可以看到,.dynsym 表包含39项.__cxa_atexit 是一个导入符号,而 __cxa_guard_acquire 则是一个导出符号.

装载与动态链接

装载与动态链接 1可执行文件的装载与进程 可执行文件只有装载到内存后才能被CPU执行.早期的程序装载十分简陋,装载的基本过程就是把程序从外部存储器中读取到内存中的某个位置. 历史有过的装载方式包括覆盖装载.页映射. 1.1 进程虚拟地址空间 程序是一个静态的概念,它就是一些预先编译好的指令和数据集合的一个文件:进程则是一个动态的概念,它是程序运行的一个过程. 每个程序被运行起来以后,都有自己的虚拟地址空间,这个虚拟地址空间的大小由计算机的硬件平台决定,具体地说是由CPU的位数决定的. 1.2 装

再探Linux动态链接 -- 关于动态库的基础知识

  在近一段时间里,由于多次参与相关专业软件Linux运行环境建设,深感有必要将这些知识理一理,供往后参考. 编译时和运行时 纵观程序编译整个过程,细分可分为编译(Compiling,指的是语言到平台相关目标文件这一层次)和链接(Linking,指目标文件到最终形成可执行文件这一层次),这个总的过程可称为编译时:就动态链接而言,还存在一个运行时,即程序在被操作系统加载的过程中,系统将该程序需要的动态库加载至内存到程序开始运行的这一段过程.明确这两个过程在一般linux开发中的地位,以及了解每个"

计算机科学基础知识(五)动态链接

一.前言 本文以类似hello world这样的简单程序为例,描述了动态连接的概念.第二章描述了整个动态链接的大概过程,随后的两章解析了程序访问动态库中的数据和调用动态库中函数的过程. 注意:阅读本文之前需要先了解relocatable object file.静态链接以及动态库和PIC这些内容. 二.动态链接的过程概述 下面的图展示了动态链接的过程: Static Linker(对于本文的场景,它就是arm-linux-ld)接收下面的输入: (1)命令行参数 (2)linker script