它记录在应用程序二进制文件本身内部(在编译时指定,更准确地说是在链接步骤中指定,用ld
):
$ readelf -d /bin/echo
Dynamic section at offset 0x5f1c contains 21 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.6]
...
(还有一些额外的列说明 elf 如何在动态部分中存储信息。但是您可以看到 libc.so.6 是硬编码的.6
后缀因为SONAME http://en.wikipedia.org/wiki/Soname)
或者甚至不了解 ELF 文件格式:
$ strings /bin/echo |grep libc.so
libc.so.6
要查找链接器如何找到库(在编译的最后一步完成),请使用gcc
option -Wl,--verbose
(这要求 gcc 传递选项--verbose
to ld
):
$ gcc a.c -Wl,--verbose
...
attempt to open /usr/lib/gcc/i686-pc-linux-gnu/4.4.4/libc.so failed
attempt to open /usr/lib/gcc/i686-pc-linux-gnu/4.4.4/libc.a failed
attempt to open /usr/lib/gcc/i686-pc-linux-gnu/4.4.4/libc.so failed
attempt to open /usr/lib/gcc/i686-pc-linux-gnu/4.4.4/libc.a failed
attempt to open /usr/lib/gcc/i686-pc-linux-gnu/4.4.4/../../../libc.so succeeded
opened script file /usr/lib/gcc/i686-pc-linux-gnu/4.4.4/../../../libc.so
opened script file /usr/lib/gcc/i686-pc-linux-gnu/4.4.4/../../../libc.so
attempt to open /lib/libc.so.6 succeeded
/lib/libc.so.6
链接器不知道任何事情.digit
后缀,它只是迭代尝试打开的所有库搜索目录libLIBNAME.so
and libLIBNAME.a
,其中 LIBNAME 是后面的字符串-l
选项。 (-lc
默认添加选项)。
第一次成功是/usr/lib/libc.so
它本身不是一个库,而是一个链接器脚本(文本文件)。这是典型的内容libc.so
script:
$ cat /usr/lib/libc.so
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf32-i386)
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux.so.2 ) )
所以,脚本/usr/lib/libc.so
比实际库更早找到,并且此脚本说明将链接哪个文件,libc.so.6
在这种情况下。
在更常见的情况下,lib___.so
是某个版本的符号链接,例如lib___.so.3.4.5
并且填写了 SONAME 字段lib___.so.3.4.5
其中说ld
链接不至lib___.so
but to lib___.so.3.4
这是另一个符号链接lib___.so.3.4.5
. The .3.4
名称将记录在二进制文件的 NEEDED 字段中。