什么是“静态共享库”

  一般,共享目标文件在创建时,其基本虚拟地址是 0。

       我们用“readelf -l”查看一个so文件的程序头表,可以查看权限(Flags)为类型为可加载(LOAD)且权限为可读可执行(R E)的段需要映射到进程虚拟地址空间中的位置(VirtAddr)是不是0。

[root@localhost 1]# readelf  -l libtest1.so

Elf file type is DYN (Shared object file)
Entry point 0x4f0
There are 6 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  LOAD           0x0000000000000000 0x0000000000000000 0x0000000000000000
                 0x00000000000006ec 0x00000000000006ec  R E    200000
  LOAD           0x00000000000006f0 0x00000000002006f0 0x00000000002006f0
                 0x00000000000001f8 0x0000000000000208  RW     200000
  ………………………………….

如果这个段需要映射到进程虚拟地址空间中的位置(VirtAddr)是0,则说明这个共享库加载到内存之后的位置是不固定的,这种共享库我们称之为“动态共享库”(Dynamic Shared Library),也就是我们常说的“动态库”。

如果这个段需要映射到进程虚拟地址空间中的位置(VirtAddr)不是0,而是一个确定的地址,这种共享库我们称之为“静态共享库”(Static Shared Library)。注意,与“静态库”有很明显的区别,从名字上就可以看出,多了“共享”。

静态共享库(Static Shared Library)有一个先天的缺陷:管理起来及其困难。你想啊,我编了一个静态共享库A,用了0x1000到0x2000的地址,别人的静态共享库如果也用了0x1000到0x2000的地址,那我俩的共享库就不能同时被加载。而且,假如我还写了另一个静态共享库B,用了0x2000到0x3000的地址,然后我发现我之前写的静态共享库A有问题,需要改一下,改完之后被改大了,要用到0x1000到0x3000的地址了。天啦噜,B的地址也要被往后改了!!!

“静态共享库”这种机制在现在看来真是让人无法理解,但是想到它是在“静态库”之后、动态共享库之前被设计出来的,放在它们俩中间的位置来看,我们就可以理解了:“静态共享库”解决了“静态库”一万个人要用printf就必须一万个人都自己加载一遍printf的定义那种丧心病狂的内存浪费。

可以这样想:“静态共享库”是对“静态库”的改进,解决了其对内存空间浪费的情况;“动态共享库”是对“静态共享库”的改进,解决了其可能造成地址冲突的情况。

其实现在还有一些“静态共享库”在被使用(因为不需要重定位,所以运行起来很快。目前有一些linux系统自己用的库是静态共享库,这些库一般都很成熟,不会有大的改动),比如Linux的“/lib64/libc.so.6”就是一个“静态共享库”,如果你用“readelf -l”看它的程序头表,可以发现这个so是被加载到了它指定的位置的。

[root@localhost 1]# readelf  -l /lib64/libc.so.6
Elf file type is DYN (Shared object file)
Entry point 0x383681ee30
There are 10 program headers, starting at offset 64
 
Program Headers:
 Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
 PHDR           0x0000000000000040 0x0000003836800040 0x0000003836800040
                 0x0000000000000230 0x0000000000000230  R E    8
 INTERP         0x000000000015a910 0x000000383695a910 0x000000383695a910
                 0x000000000000001c 0x000000000000001c  R      10
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
 LOAD           0x0000000000000000 0x0000003836800000 0x0000003836800000
                 0x0000000000189e5c 0x0000000000189e5c  R E    200000
 LOAD           0x000000000018a708 0x0000003836b8a708 0x0000003836b8a708
                 0x0000000000004f50 0x0000000000009220  RW     200000
 …………………………………

可以看到,“/lib64/libc.so.6”会被装载到“0x3836400000”开始的地址。

posted @ 2025-04-01 19:06  94那抹微笑  阅读(11)  评论(0)    收藏  举报