动态链接 (1)

来源:互联网 发布:雕刻机钻孔编程 编辑:程序博客网 时间:2024/05/23 18:39

代码共享

对于操作系统来说,程序的代码段是只读的并且和数据段是分离的。那么如果程序之间有大量共有的代码段,则可以将这些共有的代码段在不同的可执行文件之间进行共享,从而避免相同代码段的多个拷贝而导致的内存浪费。

利用虚拟内存可以很容易的做到这一点。加载库代码的物理内存页面可以很容易的被任意数量的虚拟页面所引用。因此当系统内存中有一份库代码的物理拷贝时,每个进程可通过任意虚拟地址对该库代码进行访问。

因此,人们很自然的就有了“共享库(shared library)”的想法。每个可执行文件包含对共享库的引用表明“我需要某某库”。当程序被加载的时候,系统就会检查内存中是否已加载所需要的共享库(加载其他程序时被加载),若是,将共享库的物理内存映射进可执行文件中以进行共享,否则将共享库加载到内存中。

这个过程称为动态链接因为整个链接过程是程序在执行过程中动态进行的。

动态库说明

可以将库想象成一个没有执行入口点的程序。它们和可执行文件一样有代码和数据段,但是不知道从哪里开始执行。它们只是提供一系列的库函数或变量供开始者来使用。

因此可以用同一种格式ELF(Executable and Linkable Format)来表示可执行文件和动态链接库。但两者间有一些基本的不同,如动态库不包含执行开始点的指针。ELF头部有两个互斥的标志,EXEC和DYN来标识一个ELF文件是可执行文件或共享库文件。

示例:
$ readelf -e /bin/ls | grep TypeType:                              EXEC (Executable file)  [Nr] Name              Type             Address           Offset  Type           Offset             VirtAddr           PhysAddr

在可执行文件中使用动态库

编译

当编译使用动态库链接库的程序时,生成的目标文件中会保存有对库函数或变量的引用。你需要在代码里显示的inlcude库的头文件以让编译器知道所引用的库函数或变量的类型。

链接

即使动态链接器已经为共享库做了很多的工作,但传统的链接器在创建可执行文件时仍扮演了很重要的角色。

传统的链接器需要在可执行文件中保留一个指示区域来让动态链接器知道这个可执行文件在运行时需要满足哪些依赖。可执行文件中“dynamic”这个section保存了该可执行文件所需要(NEEDED)的每个共享库。我们同样可以通过readelf命令来对该section进行查看。

$ readelf --dynamic /bin/lsdynamic section at offset 0x18e18 contains 23 entries:  Tag        Type                         Name/Value 0x0000000000000001 (NEEDED)             Shared library: [libselinux.so.1] 0x0000000000000001 (NEEDED)             Shared library: [librt.so.1] 0x0000000000000001 (NEEDED)             Shared library: [libacl.so.1] 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]...

可以看到ls这个可执行文件依赖了四个库。但是正如前面所说的,每个库文件都可以看成可执行文件,所以这些库文件也可以依赖其他的库。那么如何找出可执行文件依赖的所有库呢?很简单的方法就是递归的查看每个库文件的dynamic section,将其中NEEDED的库文件找出来。命令“ldd”提供了这种功能:

$ ldd /bin/lslinux-vdso.so.1 =>  (0x00007fff789d9000)libselinux.so.1 => /lib/x86_64-linux-gnu/libselinux.so.1 (0x00007f2cb8b2a000)librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007f2cb8922000)libacl.so.1 => /lib/x86_64-linux-gnu/libacl.so.1 (0x00007f2cb8719000)libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f2cb8385000)libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007f2cb8181000)/lib64/ld-linux-x86-64.so.2 (0x00007f2cb8d6a000)libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f2cb7f62000)libattr.so.1 => /lib/x86_64-linux-gnu/libattr.so.1 (0x00007f2cb7d5d000)







原创粉丝点击