共享库之动态连接

Linux ld命令 将目标文件连接为可执行程序,Linux ldd命令 打印程序或者库文件所依赖的共享库列表,Linux ldconfig命令 动态链接库管理命令。 阅读详情
   静态链接浪费内存和磁盘空间、模块更新困难等问题,因此寻找一种更好的办法来组织程序模块。

   静态链接对程序的更新、部署和发布也会带来很多麻烦。

 

动态链接:

      就是不对那些组成程序的目标文件进行链接,等到程序要运行时才进行链接。

 

动态链接的方式使得开发过程中各个模块更加独立、耦合度更小,便于不同的开发者和开发组织之间进行独立的开发和测试。

动态链接还有一个特点就是程序在运行时可以动态的选择加载各种程序模块,使得插件成为可能。

Linux系统中,ELF动态链接文件被称为动态共享对象(DSO,Dynamic Shared Objects),简称共享对象,它们一般都是以“.so”为扩展名;动态链接文件被称为动态链接库。在windows下为.dll。

/*Program1.c */

#include "Lib.h"

int main()

{

        foobar(1);

        return 0;

}

 

/*Program2.c*/

#include "Lib.h"

int main()

{

        foobar(2);

        return 0;

}

/*Lib.c*/

#include <stdio.h>

void foobar(int i)

{

        printf("Printing from Lib.so %d\n",i);

}

/*Lib.h*/

#ifndef LIB_H

#define LIB_H

void foobar(int i); 

#endif

horst@debian:~/horstdemo/simpleDynamic$ gcc -fPIC -shared -o mylib.so lib.c

将Lib.c 编译成为一个共享对象文件,‘-shared’表示产生共享对象

-fPIC(Position Independent Code)表示使用地址无关代码技术来产生输出文件

horst@debian:~/horstdemo/simpleDynamic$ gcc -o program1 program1.c ./mylib.so

利用 ./mylib.so分别进行编译链接。

运行结果:

horst@debian:~/horstdemo/simpleDynamic$ ./program1 &
[1] 14969
horst@debian:~/horstdemo/simpleDynamic$ Printing from lib.so 1

查看进程的虚拟地址空间:

可以看到有Lib.so映射文件。

 horst@debian:~/horstdemo/simpleDynamic$ cat /proc/14969/maps
08048000-08049000 r-xp 00000000 08:05 395370     /home/horst/horstdemo/simpleDynamic/program1
08049000-0804a000 rw-p 00000000 08:05 395370     /home/horst/horstdemo/simpleDynamic/program1
b7e35000-b7e36000 rw-p b7e35000 00:00 0
b7e36000-b7f8b000 r-xp 00000000 08:01 1971754    /lib/i686/cmov/libc-2.7.so
b7f8b000-b7f8c000 r--p 00155000 08:01 1971754    /lib/i686/cmov/libc-2.7.so
b7f8c000-b7f8e000 rw-p 00156000 08:01 1971754    /lib/i686/cmov/libc-2.7.so
b7f8e000-b7f91000 rw-p b7f8e000 00:00 0
b7f9f000-b7fa0000 rw-p b7f9f000 00:00 0
b7fa0000-b7fa1000 r-xp 00000000 08:05 395365     /home/horst/horstdemo/simpleDynamic/mylib.so
b7fa1000-b7fa2000 rw-p 00000000 08:05 395365     /home/horst/horstdemo/simpleDynamic/mylib.so
b7fa2000-b7fa4000 rw-p b7fa2000 00:00 0
b7fa4000-b7fa5000 r-xp b7fa4000 00:00 0          [vdso]
b7fa5000-b7fbf000 r-xp 00000000 08:01 1962242    /lib/ld-2.7.so
b7fbf000-b7fc1000 rw-p 0001a000 08:01 1962242    /lib/ld-2.7.so
bfdab000-bfdc0000 rw-p bffeb000 00:00 0          [stack]

链接时重定位(静态链接);装载时重定位(动态链接)

地址无关代码:PIC,Position-independent Code,把指令中那些需要修改的部分分离出来,跟数据部分放在一起,这样指令部分就可以保持不变,而数据部分可以再每个进程中拥有个副本。

 

                       指令跳转、调用                          数据访问

模块内部      (1)相对跳转和调用                   (2)相对地址访问

模块外部      (3)间接跳转和调用(GOT)     (4)间接访问(GOT)

 

如果一个共享对象lib.so中定义了一个全局变量G,而进程A和B都使用了lib.so,那么当进程A改变这个全局变量G的值的时,进程B中G会受到影响么?

不会,因为当lib.so被两个进程加载时,它的数据段部分在每个进程中都有独立的副本,从这个角度看,共享对象中的全局变量实际上和定义在程序内部的全局变量没什么区别。如果是线程,则有影响。

 

延迟绑定:

动态链接比i链接慢的主要原因是动态链接下对于全局静态的数据访问要进行复杂的GOT定位,然后间接寻址.

 

由于很多函数在程序执行过程中不一定被用到(错误处理函数,特殊功能模块),ELF采用了一种叫延迟绑定(Lazy Binding)的做法,基本思想就是当函数第一次被用到时才进行绑定。


操作系统如何确定动态连接器?

 

在动态链接的ELF可执行文件中,有一个专门的段叫做“.interp”,如果我们使用objdump来查看:

horst@debian:~/horstdemo/simpleDynamic$ objdump -s ./program1

./program1:     file format elf32-i386

Contents of section .interp:
 8048114 2f6c6962 2f6c642d 6c696e75 782e736f  /lib/ld-linux.so
 8048124 2e3200 

动态链接ELF中最重要的结构应该是“.dynamic”段,这个段里面保存了动态连接器所需要的基本信息,比如依赖哪些共享对象、动态链接符号表的位置、动态链接重定位表的位置、共享对象初始化代码的地址等。

使用readelf工具查看“.dynamic”段的内容:

horst@debian:~/horstdemo/simpleDynamic$ readelf -d ./program1

Dynamic section at offset 0x588 contains 22 entries:
  Tag        Type                         Name/Value
 0x00000001 (NEEDED)                     Shared library: [./mylib.so]
 0x00000001 (NEEDED)                     Shared library: [libc.so.6]
 0x0000000c (INIT)                       0x804835c
 0x0000000d (FINI)                       0x804854c
 0x00000004 (HASH)                       0x8048148
 0x6ffffef5 (GNU_HASH)                   0x8048188
 0x00000005 (STRTAB)                     0x8048274
 0x00000006 (SYMTAB)                     0x80481c4
 0x0000000a (STRSZ)                      143 (bytes)
 0x0000000b (SYMENT)                     16 (bytes)
 0x00000015 (DEBUG)                      0x0
 0x00000003 (PLTGOT)                     0x8049664
 0x00000002 (PLTRELSZ)                   24 (bytes)
 0x00000014 (PLTREL)                     REL
 0x00000017 (JMPREL)                     0x8048344

mylib.so中的foobar函数称为导出函数

为了表示动态链接这些模块之间的符号导出与导入关系,ELF专门有一个叫做动态符号表的段用来保存这些信息。这个段叫做“.dynsym”。

可以使用如下命令来查看动态符号表:

horst@debian:~/horstdemo/simpleDynamic$ readelf -sD ./mylib.so

Symbol table for image:
  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name
    9   0: 00000308     0    FUNC GLOBAL DEFAULT   9 _init
    7   0: 0000160c     0  NOTYPE GLOBAL DEFAULT ABS _edata
    4   0: 00000000   613    FUNC GLOBAL DEFAULT UND sleep
    2   0: 00000000     0  NOTYPE   WEAK DEFAULT UND _Jv_RegisterClasses
    1   0: 00000000     0  NOTYPE   WEAK DEFAULT UND __gmon_start__
   10   0: 0000044c    57    FUNC GLOBAL DEFAULT  11 foobar
    6   1: 00001614     0  NOTYPE GLOBAL DEFAULT ABS _end
   11   1: 000004c8     0    FUNC GLOBAL DEFAULT  12 _fini
    5   2: 00000000   267    FUNC   WEAK DEFAULT UND __cxa_finalize
    8   2: 0000160c     0  NOTYPE GLOBAL DEFAULT ABS __bss_start
    3   2: 00000000    54    FUNC GLOBAL DEFAULT UND printf

Symbol table of `.gnu.hash' for image:
  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name
    6   0: 00001614     0  NOTYPE GLOBAL DEFAULT ABS _end
    7   0: 0000160c     0  NOTYPE GLOBAL DEFAULT ABS _edata
    8   1: 0000160c     0  NOTYPE GLOBAL DEFAULT ABS __bss_start
    9   1: 00000308     0    FUNC GLOBAL DEFAULT   9 _init
   10   2: 0000044c    57    FUNC GLOBAL DEFAULT  11 foobar
   11   2: 000004c8     0    FUNC GLOBAL DEFAULT  12 _fini

动态链接的文件中,也有类似静态链接的重定位表,分别叫做“.rel.dyn”和“.rel.plt”,他们分别相当于“.rel.text”和“.rel.data”。

 

查看动态链接文件的重定位表:

horst@debian:~/horstdemo/simpleDynamic$ readelf -r ./mylib.so

Relocation section '.rel.dyn' at offset 0x2c8 contains 4 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
00001608  00000008 R_386_RELATIVE   
000015e0  00000106 R_386_GLOB_DAT    00000000   __gmon_start__
000015e4  00000206 R_386_GLOB_DAT    00000000   _Jv_RegisterClasses
000015e8  00000506 R_386_GLOB_DAT    00000000   __cxa_finalize

Relocation section '.rel.plt' at offset 0x2e8 contains 4 entries:
 Offset     Info    Type            Sym.Value  Sym. Name
000015f8  00000107 R_386_JUMP_SLOT   00000000   __gmon_start__
000015fc  00000307 R_386_JUMP_SLOT   00000000   printf
00001600  00000407 R_386_JUMP_SLOT   00000000   sleep
00001604  00000507 R_386_JUMP_SLOT   00000000   __cxa_finalize

动态链接的步骤和实现:

动态链接的步骤基本分为三步:先启动动态连接器本身,然后装载所有需要的共享对象,最后是重定位和初始化。

但是对于动态链接器本身来说,它的重定位工作是由谁来完成的? 

动态连接器本身通过自举(Bootstrap)来完成。

完成基本自举之后,动态连接器将可执行文件和连接器本身的符号表都合并到一个符号表当中,我们可以称它为全局符号表(Global Symbol Table)。

动态连接器按照各个模块之间的依赖关系,当有两个不同的模块定义了同一个符号时怎么办?

当一个符号需要被加入全局符号表时,如果相同的符号已经存在,则后加入的符号被忽略。

显示运行时链接:

动态库的装载则是通过一些列由动态连接器提供的API,具体是4个函数:打开动态库(dlopen)、查找符号(dlsym)、错误处理(dlerror)、以及关闭动态库(dlclose)。

dlopen()函数用来打开动态库,并将其加载到进程的地址空间,完成初始化过程。

void  *dlopen(const char *filename, int flag);

 

dlsym(),我们通过该函数找到所需要的符号。

dlsym(void  *handle,  char  *symbol);



[GXYCTF2019]BabyUpload1 -- .htaccess文件解析与蚁剑实战指南 本文深入解析了[GXYCTF2019]BabyUpload1文件上传漏洞的实战利用。通过绕过后缀名与内容检测,上传包含PHP代码的.jpg文件,并利用.htaccess文件强制服务器将其解析为PHP脚本。文章详细介绍了.htaccess的原理、构造方法、Content-Type绕过技巧,并演示了如何使用中国蚁剑连接Webshell获取Flag,为Web安全学习提供了完整实战指南。 阅读详情

相关推荐

【MM小贴士】关于SAP系统中关税的处理方式

的运费,这部分来讲,我们关税的计价基础,就应该是货物价值+包邮到中国港口的运费,完后进行报关操作,缴纳关税,后半段从中国港口拉回到企业里面的运输费,就会做到费用里面去,而不是计入到存货成本。1、我们自己的企业和国外厂家A购买一项物资,厂家A的报价会分成几个组成部分货物本身的价值或者货物本身的价值+到国外港口的运费或者货物本身的价值+到中国港口的运费或者货物本身的价值+包邮到你们自己企业的整体运费。所以我的关税就是不确定的。重点是运费是哪一段的运费,如何结算,结算的货币,何时能够确定运费。.........

竹大的博客 9023

全局变量和extern详解

全局变量和extern详解声明与定义extern 声明与定义 首先讲一下声明与定义 声明不等于定义,声明只是指出了变量的名字,并没有为其分配存储空间;定义指出变量名字同时为变量分配存储空间,定义包含了声明 extern int i; //声明变量i,但没分配存储空间,还不能使用, 可以出现很多次,下面的三种情况只能出现一次 int i; //定义了变量i,并分配了空间,可以使用 extern int a =0 //定义一个全局变量a 并给初值 int a =0;//定义一个全局

nbu_dahe的博客 5307

Python爬虫实战:5分钟搞定Web of Science文献批量导出与解析(附完整代码)

本文提供了一套利用Python爬虫技术,快速实现Web of Science文献批量提取与解析的完整方案。通过解析官方导出的HTML文件,结合BeautifulSoup和pandas库,可将文献数据自动转换为结构化的Excel/CSV表格,帮助科研人员高效管理文献信息,节省大量手动整理时间。

weixin_29050513的博客 1164

extern详解

extern关键字详解

TTdreamloong的博客 4万+

天龙八部源码深度解析:从宠物系统到副本机制(C++游戏开发实战)

本文深度解析《天龙八部》源码架构,重点剖析宠物系统状态机实现与副本动态加载机制等核心模块。通过C++代码示例展示宠物AI状态迁移逻辑和副本场景管理技术,为现代游戏开发提供兼容性改造方案与设计启示。适合游戏开发者学习经典MMORPG的工程化实现路径。

weixin_29011239的博客 386

Power domain 划分该如何下手

假如PD1比PD3更always on的话,我们只需要插入普通buffer即可,因为PD3 on,PD1也肯定是ON,PD1 off,PD3肯定时off,PD1能cover PD3的电源情况,因此使用普通buffer也可,但是处于省电角度,我们还是使用AO buffer;在我们做多power domain时,在切分power domain时,需要谨慎,稍有不慎,就会出现congestion以及timing问题,那问题来了,我们在切分power domain时有什么考究么,今天小编就和大家一起讨论讨论。

芯冰乐 207

c语言全局变量(extern)和静态全局变量(static)的使用、拓展作用域(全局、局部等)

c、c++基本知识点:作用域、全局变量(extern)、局部变量等

weixin_55491446的博客 1万+

【Codecs系列】HEVC-SCC(一):核心技术介绍

DATE: 2020.6.4【Tags: HEVC SCC】 1、参考网址 2、SCC简介 3、HEVC-SCC核心技术

优快云明星博主,认证博客专家,视频、Matlab领域优质创作者。 4803

全局变量 extern

全局变量(外部变量)是在函数的外部定义的,它的作用域为从变量的定义处开始,到本程序文件的末尾。在此作用域内,全局变量可以为本文件中各个函数所引用。编译时将全局变量分配在静态存储区。    有时需要用extern来声明全局变量,以扩展全局变量的作用域。    1. 在一个文件内声明全局变量    如果外部变量不在文件的开头定义,其有效的作用范围只限于定义处到文件终了。如果在定义点之

我不会编程,但不是完全不会,我会一点点 1276

Hadoop在大数据领域的电商数据分析案例

随着电商行业的迅猛发展,每天都会产生海量的数据,如用户浏览记录、购买行为、商品信息等。如何从这些数据中提取有价值的信息,为电商企业的决策提供支持,成为了电商企业面临的重要问题。Hadoop作为一个开源的分布式计算平台,具有高可靠性、高扩展性和高效性等特点,能够很好地处理大数据。本文的目的就是通过实际案例,详细介绍Hadoop在电商数据分析中的应用,范围涵盖了从数据采集、存储到分析的整个流程。本文首先介绍背景信息,让读者了解Hadoop在电商数据分析中的重要性和应用场景。

Java大师兄的博客 1178

CAPL与人工智能结合

AI模型是指通过机器学习算法训练得到的模型,可以用于分类、回归、聚类等任务。常见的AI模型包括神经网络、支持向量机、决策树等。在汽车电子系统中,AI模型可以用于故障诊断、驾驶行为分析、自动驾驶等场景。实时决策是指在汽车电子系统中,根据AI模型的预测结果,实时做出决策。实时决策可以用于自动驾驶、故障诊断等场景。通过本文的学习,读者应该对CAPL与人工智能结合有了初步的了解,并能够编写复杂的CAPL脚本。

闲人编程的博客 1479

深入理解C语言中的extern关键字:跨文件共享的全局变量和函数

本文旨在深入探讨C语言中的extern关键字,为开发者提供关于其在跨文件共享全局变量和函数方面的全面理解。文章首先概述了extern关键字的定义和基本用法,随后详细分析了它在不同上下文中的具体应用,包括全局变量和函数声明。最后,通过技术总结,强调了extern在编程中的重要性。extern关键字是C语言中的一个修饰符,用于声明全局变量和函数的引用。它用于告诉编译器,某个全局变量或函数的定义位于其他文件中。以下是extern全局变量声明:在文件中使用extern。

极客代码 2万+

一条时间轴上的商品供给:商品供给域事件全景、八大子域事件清单与事件契约规范的工程推演

本文以虚构连锁零售企业“青禾鲜市”为例,用事件风暴重新梳理商品供给域:先剖析同词异义、状态模糊、隐式依赖与被动兜底四类冲突,再以时间轴、八条子域泳道与关键事件铺出全景地图,确立一个事件只有一个户口;随后为总店商品、门店商品、价格、库存、质量、标签、变更通知与操作日志列出聚合、事件、命令与策略,并统一命名、信封结构、版本与幂等规范。程序体检把初稿14个问题清零,仿真显示按聚合版本号更新可售视图可将误判从两位数百分比降到0.019%。文末给出四轮工作坊节奏与新品引入、全国调价、批次召回走查剧本。

曾经“等你生日那天”都遥远得像未来,如今却可欢愉的挥手说“下个十年见” 5万+

Linux下动态共享库 连接和加载路径

1. 连接时找不到某一个函数,出现“ xxxxx undefined”,应该就是连接时找不到相应的动态库,连接时动态库的路径如下: 1> 默认路径是:/lib,  /usr/lib/,  /usr/local/lib 2> -L: 指定连接时动态库的路径 3> LD_LIB

finding的专栏 7970

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

第7章“链接”:如何动态连接共享库、从应用程序中加载和链接共享库

7.10 动态链接共享库;7.11 从应用程序中加载和链接共享库;7.12 *与位置无关的代码

明朗晨光的专栏 1934

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

linux连接当前目录动态库,linux C 动态共享库编译链接

1.1.1linux编写so文件的方式1首先gcc编译的时候要加-fPIC选项,-fPIC是告诉gcc生成一个与位置无关的代码2gcc链接的时候要加-shared选项,意思是生成一个so共享库。对于linux或者unix,一个so文件,文件扩展名必须是so,文件名的前三个字母必须是lib1.1.2linux使用sogcc链接的时候需要加-L.代表从当前目录下找相关的so文件,-l文件名(但不包括文...

weixin_36147585的博客 527

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

linux下动态共享库的创建,使用与更新(包括ldconfig的使用)g++ -WI -soname

-Wl,-soname  -Wl 告诉编译器将后面的参数传递到连接器。而 -soname 指定了共享库的 soname  这个soname的存在是为了兼容方便。  比如:      有一个程序ap1,以及一个库libtest.so.1      ap1启动的时候需要libtest.so.1      如果链接的时候直接把libtest.so.1传给了ap1,那么

missingu1314的专栏 1289

Linux gcc编译库,如何在Linux上使用GCC编译共享库

原文链接 http://t.cn/RPzyNB3对于任何程序员来说,库都是不可缺少的工具.它们是使用已经存在的代码,编译并可以唯你使用的.它们通常提供一般性的功能,像可以存储任何数据的“链表”和“二叉树”,或者某些特殊的功能,比如数据库服务(如MySQL).绝大多数软件项目包含若干组件,这些组件可能在之后的其它项目中会被用到,或者你构建项目的时候只是想要分出来而已.当你有可重用或者逻辑上不相关的函...

weixin_39934085的博客 163

如何在Linux上使用GCC编译共享库

原文链接 http://t.cn/RPzyNB3 对于任何程序员来说,库都是不可缺少的工具.它们是使用已经存在的代码,编译并可以唯你使用的.它们通常提供一般性的功能,像可以存储任何数据的“链表”和“二叉树”, 或者某些特殊的功能,比如数据库服务(如MySQL).绝大多数软件项目包含若干组件,这...

chenhang8946的博客 185

linux编译的时候带上库,如何在Linux上使用GCC编译共享库

原文链接 http://t.cn/RPzyNB3对于任何程序员来说,库都是不可缺少的工具.它们是使用已经存在的代码,编译并可以唯你使用的.它们通常提供一般性的功能,像可以存储任何数据的“链表”和“二叉树”,或者某些特殊的功能,比如数据库服务(如MySQL).绝大多数软件项目包含若干组件,这些组件可能在之后的其它项目中会被用到,或者你构建项目的时候只是想要分出来而已.当你有可重用或者逻辑上不相关的函...

weixin_39619170的博客 290
上一篇: python学习之路-继承
下一篇: linux memwatch的内存检测-double-free
horst_hu
博客等级 码龄15年 38粉丝 34原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值