科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道Linux操作系统动态函式库探究(一) (3)

Linux操作系统动态函式库探究(一) (3)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

与使用动态函式库的执行档 test 比较起来,大了约 70倍 (215364/3004)。因此,整体来说,在使用的环境中使用动态函式库并且经过 strip 处理的话,可以让整体的空间较为精简。

作者:www.linuxbyte.net 来源:www.linuxbyte.net 2007年10月20日

关键字: 操作系统 动态 Linux

  • 评论
  • 分享微博
  • 分享邮件
 

与使用动态函式库的执行档 test 比较起来,大了约 70倍 (215364/3004)。因此,整体来说,在使用的环境中使用动态函式库并且经过 strip 处理的话,可以让整体的空间较为精简。许多执行档都会用到同一组的函式库,像 libc 中的函式是每个执行档都会使用到的,若是使用动态函式库,则可以尽量减少同样的函式库内容重复存在系统中,进而达到节省空间的目的。

笔者一年前曾写过一个可以用来删去动态函式库中不必要函式的工具,针对这个只用到了 printf 的程序来产生新的 libc.so 的话,我们可以得到一个精简过的 libc.so 大小约为 219068 bytes :

[root@hlchoua lib]# ls -l libc.so* 
-rwxr-xr-x 1 root root 219068 Nov 2 04:47 libc.so 
lrwxrwxrwx 1 root root 7 Nov 1 03:40 libc.so.6 -> libc.so

与静态联结的执行档大小 215364 bytes 比较起来,若是在这个环境中使用了动态函式库的话成本约为 3004 + 219068 =222072 bytes,不过这是只有一个执行档的情况下,使用动态函式库的环境会小输给使用静态联结的环境,在一个基本的 Linux 环境中,如果大量的使用动态函式库的话,像是有 2 个以上的执行档的话,那用动态函式库的成本就大大的降低了,像如果两个执行档都只用到了 printf,那静态联结的成本为 215364 *2 =430728 bytes,而使用动态函式库的成本为3004 *2 + 219068=225076 bytes,两者相差约一倍。

很明显的,我们可以看到动态函式库在 Linux 环境中所发挥的妙用,它大幅的降低了整体环境的持有成本,提高了环境空间的利用率。ld-linux.so.2,在 RedHat 6.1 中,我们可以在 /lib 或是 /usr/lib 目录底下找到许多系统上所安装的动态函式库,在文章的这个部分,笔者将把整个函式库大略的架构作一个说明。其实 Linux 跟 Windows 一样,提供了一组很基本的动态函式库,在 Windows 上面我们知道 kernel32.dll 提供了其它动态函式库基本的函式呼叫,而在 Linux 上面则透过 ld-linux.so.2 提供了其它动态函式库基本的函式,在笔者电脑的 RedHat6.1 上,ld-linux.so.2 是透过 link 到 ld-2.1.2.so(这部分需视各人所使用的 glibc 版本不同而定):

-rwxr-xr-x 1 root root 368878 Jan 20 14:28 ld-2.1.2.so 
lrwxrwxrwx 1 root root 11 Jan 20 14:28 ld-linux.so.2 -> ld-2.1.2.so

ld-linux.so 是属於 Glibc (GNU C Library) 套件的一部分,只要是使用 Glibc 动态函式库的环境,就可以见到 ld-linux.so 的踪影。

接下来,我们透过指令 ldd 来验证出各个函式库间的阶层关系,首先如下图我们执行了 ”ldd ls”、”ldd pwd” 与 “ldd vi”,可以看出各个执行档呼叫了哪些动态函式库,像执行档 ls 呼叫了 /lib/libc.so.6 (0x40016000) 与 /lib/ld-linux.so.2 (0x40000000),而括号内的数字为该函式库载入记忆体的位置,在本文的稍後,会介绍到函式库载入时的细节,到时读者会有更深入的了解。

其实我们不难发现,在 Linux 上使用动态函式库的执行档,几乎都会去呼叫 libc.so.6 与 ld-linux.so.2 这两个动态函式库,笔者过去修改 Glibc 的套件时,也了解到在 Linux 中函式库的关系,ld-linux.so.2 算是最底层的动态函式库,它本身为静态联结,主要的工作是提供基本的函式给其他的函式库,而我们最常会呼叫的 libc.so.6 则是以 ld-linux.so.2 为基础的一个架构完成的动态函式库,它几乎负责了所有我们常用的标准 C 函式库,像是我们在 Linux 下写的 Socket 程序,其中的connect()、bind()、send() .....之类的函式,都是由 libc.so.6 所提供的。

也因此,libc.so.6 的大小也是相当可观的,在 RedHat 6.1 中经过 strip 後,大小约为 1052428 bytes。

[root@hlchoua /root]# ldd /bin/ls 
libc.so.6 => /lib/libc.so.6 (0x40016000) 
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 
[root@hlchoua /root]# ldd /bin/pwd 
libc.so.6 => /lib/libc.so.6 (0x40016000) 
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 
[root@hlchoua /root]# ldd /bin/vi 
libtermcap.so.2 => /lib/libtermcap.so.2 (0x40016000) 
libc.so.6 => /lib/libc.so.6 (0x4001b000) 
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)

如下,我们透过 ldd 验证 vi 所用到的动态函式库 /lib/libtermcap.so.2,它本身是呼叫了 libc.so.6 的函式所组成的。

[root@hlchoua /root]# ldd /lib/libtermcap.so.2 
libc.so.6 => /lib/libc.so.6 (0x40007000) 
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x80000000)

接下来,我们依序测试了 /lib/libc.so.6 与 /lib/ld-linux.so.2:

[root@hlchoua /root]# ldd /lib/libc.so.6 
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 
[root@hlchoua /root]# ldd /lib/ld-linux.so.2 
statically linked

我们可以清楚的明白 ld-linux.so.2 负责了最基础的函式,而 libc.so.6 再根据这些基本的函式架构了完整的 C 函式库,供其它的动态函式库或是应用程序来呼叫。

透过笔者所写的一个 ELF 工具程序(注二),我们也可以清楚的看到 libc.so.6呼叫了 ld-linux.so.2 哪些函式:

[root@hlchoua /root]# /I-elf /lib/libc.so.6|more 
======================================================== 
open_target_file:/lib/libc.so.6 
==>ld-linux.so.2 
__register_frame_table 
cfsetispeed 
xdr_int32_t 
utmpname 
_dl_global_scope_alloc 
__strcasestr 
hdestroy_r 
rename 
__iswctype_l 
__sigaddset 
xdr_callmsg 
pthread_setcancelstate 
xdr_union 
__wcstoul_internal 
setttyent 
strrchr 
__sysv_signal ...┅(more)

其实,ldd 指令为一个 shell script 的档案,它主要是透过呼叫 ”run-time dynamic linker” 的命令,并以 LD_TRACE_LOADED_OBJECTS 为参数来秀出这些结果的。

如下,就是我们不透过 ldd 指令直接以 eval 搭配 LD_TRACE_LOADED_OBJECTS参数来检视 libcrypt.So.1 与 libm.so.6这两个动态函式库的结果。

[root@hlchoua /root]# 
eval LD_TRACE_LOADED_OBJECTS=1 /lib/libcrypt-2.1.2.so 
libc.so.6 => /lib/libc.so.6 (0x40016000) 
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000) 
[root@hlchoua /root]# eval LD_TRACE_LOADED_OBJECTS=1 /lib/libm.so.6 
libc.so.6 => /lib/libc.so.6 (0x40016000) 
/lib/ld-linux.so.2 => /lib/ld-linux.so.2 (0x40000000)
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章