搞清可执行程序(动态库)所依赖的动态库信息是非常有帮助的。
系统信息:
Linux netview 4.4.0-101-generic #124~14.04.1-Ubuntu SMP Fri Nov 10 19:06:11 UTC 2017 i686 i686 i686 GNU/Linux
# ldd `which gdb`
linux-gate.so.1 => (0xb7737000)
libreadline.so.6 => /usr/local/lib/libreadline.so.6 (0xb76fa000)
libdl.so.2 => /lib/i386-linux-gnu/libdl.so.2 (0xb76da000)
libncurses.so.5 => /lib/i386-linux-gnu/libncurses.so.5 (0xb76b4000)
libtinfo.so.5 => /lib/i386-linux-gnu/libtinfo.so.5 (0xb7692000)
libz.so.1 => /lib/i386-linux-gnu/libz.so.1 (0xb7678000)
libm.so.6 => /lib/i386-linux-gnu/libm.so.6 (0xb7632000)
libpython3.4m.so.1.0 => /usr/lib/i386-linux-gnu/libpython3.4m.so.1.0 (0xb7251000)
libpthread.so.0 => /lib/i386-linux-gnu/libpthread.so.0 (0xb7234000)
libexpat.so.1 => /lib/i386-linux-gnu/libexpat.so.1 (0xb720b000)
liblzma.so.5 => /lib/i386-linux-gnu/liblzma.so.5 (0xb71e5000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb7034000)
/lib/ld-linux.so.2 (0xb7739000)
libutil.so.1 => /lib/i386-linux-gnu/libutil.so.1 (0xb7030000)
# ldd `gcc -print-file-name=libreadline.so.6`
linux-gate.so.1 => (0xb77cf000)
libtinfo.so.5 => /lib/i386-linux-gnu/libtinfo.so.5 (0xb7750000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb759f000)
/lib/ld-linux.so.2 (0xb77d1000)
ldd `gcc -print-file-name=libpthread.so.0`
linux-gate.so.1 => (0xb772a000)
libc.so.6 => /lib/i386-linux-gnu/libc.so.6 (0xb753e000)
/lib/ld-linux.so.2 (0xb772c000)
# readelf -d `which gdb`
Dynamic section at offset 0x4d2ec4 contains 34 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libreadline.so.6]
0x00000001 (NEEDED) Shared library: [libdl.so.2]
0x00000001 (NEEDED) Shared library: [libncurses.so.5]
0x00000001 (NEEDED) Shared library: [libtinfo.so.5]
0x00000001 (NEEDED) Shared library: [libz.so.1]
0x00000001 (NEEDED) Shared library: [libm.so.6]
0x00000001 (NEEDED) Shared library: [libpython3.4m.so.1.0]
0x00000001 (NEEDED) Shared library: [libpthread.so.0]
0x00000001 (NEEDED) Shared library: [libexpat.so.1]
0x00000001 (NEEDED) Shared library: [liblzma.so.5]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000c (INIT) 0x8089c24
0x0000000d (FINI) 0x83640bc
0x00000019 (INIT_ARRAY) 0x851beb8
0x0000001b (INIT_ARRAYSZ) 4 (bytes)
0x0000001a (FINI_ARRAY) 0x851bebc
0x0000001c (FINI_ARRAYSZ) 4 (bytes)
0x6ffffef5 (GNU_HASH) 0x80481ac
0x00000005 (STRTAB) 0x80685a4
0x00000006 (SYMTAB) 0x80509d4
0x0000000a (STRSZ) 120269 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000015 (DEBUG) 0x0
0x00000003 (PLTGOT) 0x851c000
0x00000002 (PLTRELSZ) 3512 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x8088e6c
0x00000011 (REL) 0x8088c8c
0x00000012 (RELSZ) 480 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x8088aec
0x6fffffff (VERNEEDNUM) 6
0x6ffffff0 (VERSYM) 0x8085b72
0x00000000 (NULL) 0x0
# readelf -d `gcc -print-file-name=libreadline.so.6`
Dynamic section at offset 0x38b88 contains 26 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libtinfo.so.5]
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x0000000e (SONAME) Library soname: [libreadline.so.6]
0x0000000c (INIT) 0xb0fc
0x0000000d (FINI) 0x2e484
0x00000019 (INIT_ARRAY) 0x39278
0x0000001b (INIT_ARRAYSZ) 4 (bytes)
0x0000001a (FINI_ARRAY) 0x3927c
0x0000001c (FINI_ARRAYSZ) 4 (bytes)
0x6ffffef5 (GNU_HASH) 0x138
0x00000005 (STRTAB) 0x45ec
0x00000006 (SYMTAB) 0x15ac
0x0000000a (STRSZ) 13381 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000003 (PLTGOT) 0x3a000
0x00000002 (PLTRELSZ) 848 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0xadac
0x00000011 (REL) 0x80dc
0x00000012 (RELSZ) 11472 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffe (VERNEED) 0x803c
0x6fffffff (VERNEEDNUM) 1
0x6ffffff0 (VERSYM) 0x7a32
0x6ffffffa (RELCOUNT) 1172
0x00000000 (NULL) 0x0
# readelf -d `gcc -print-file-name=libpthread.so.0`
Dynamic section at offset 0x18eb8 contains 31 entries:
Tag Type Name/Value
0x00000001 (NEEDED) Shared library: [libc.so.6]
0x00000001 (NEEDED) Shared library: [ld-linux.so.2]
0x0000000e (SONAME) Library soname: [libpthread.so.0]
0x0000000c (INIT) 0x433c
0x0000000d (FINI) 0x114d0
0x00000019 (INIT_ARRAY) 0x18dc8
0x0000001b (INIT_ARRAYSZ) 8 (bytes)
0x0000001a (FINI_ARRAY) 0x18dd0
0x0000001c (FINI_ARRAYSZ) 4 (bytes)
0x00000004 (HASH) 0x16e34
0x6ffffef5 (GNU_HASH) 0x198
0x00000005 (STRTAB) 0x24b4
0x00000006 (SYMTAB) 0xed4
0x0000000a (STRSZ) 5163 (bytes)
0x0000000b (SYMENT) 16 (bytes)
0x00000003 (PLTGOT) 0x19000
0x00000002 (PLTRELSZ) 616 (bytes)
0x00000014 (PLTREL) REL
0x00000017 (JMPREL) 0x40d4
0x00000011 (REL) 0x3e7c
0x00000012 (RELSZ) 600 (bytes)
0x00000013 (RELENT) 8 (bytes)
0x6ffffffc (VERDEF) 0x3b9c
0x6ffffffd (VERDEFNUM) 16
0x0000001e (FLAGS) STATIC_TLS
0x6ffffffb (FLAGS_1) Flags: NODELETE INITFIRST
0x6ffffffe (VERNEED) 0x3dcc
0x6fffffff (VERNEEDNUM) 2
0x6ffffff0 (VERSYM) 0x38e0
0x6ffffffa (RELCOUNT) 63
0x00000000 (NULL) 0x0
NOTE: 有个比较奇怪的库 linux-gate.so.1 , 其实它不是一个真正的动态库,它是不存在flash上的。
leon@netview:~$ ldd linux-gate.so.1
ldd: ./linux-gate.so.1: No such file or directory
leon@netview:~$ readelf -d `gcc -print-file-name=linux-gate.so.1`
readelf: Error: 'linux-gate.so.1': No such file
既然是不存在的库,那么为什么会出现在ldd命令显示的动态库列表中呢? 请参考 Linux Virtual Dynamic Shared Objects
Linux Virtual Dynamic Shared Objects
在早期的 x86 处理器中,用户程序与管理服务之间的通信通过软中断实现。 随着处理器速度的提高,这已成为一个严重的瓶颈。 自 Pentium® II 处理器开始,Intel® 引入了 Fast System Call 装置来提高系统调用速度, 即采用 SYSENTER 和 SYSEXIT 指令,而不是中断。
您所看到的 linux-vdso.so.1 是个虚拟库,或者说是 Virtual Dynamic Shared Object,它只存在于程序的地址空间当中。 在旧版本系统中该库为 linux-gate.so.1。 该虚拟库为用户程序以处理器可支持的最快的方式 (对于特定处理器,采用中断方式;对于大多数最新的处理器,采用快速系统调用方式) 访问系统函数提供了必要的逻辑 。
脚本信息:
leon@netview:~$
leon@netview:~$ ls -al `which ldd`
-rwxr-xr-x 1 root root 5425 Jun 17 04:41 /usr/bin/ldd
leon@netview:~$
leon@netview:~$
leon@netview:~$ file `which ldd`
/usr/bin/ldd: Bourne-Again shell script, ASCII text executable
leon@netview:~$
脚本内容:
#! /bin/bash
# Copyright (C) 1996-2014 Free Software Foundation, Inc.
# This file is part of the GNU C Library.
# The GNU C Library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
# License as published by the Free Software Foundation; either
# version 2.1 of the License, or (at your option) any later version.
# The GNU C Library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
# You should have received a copy of the GNU Lesser General Public
# License along with the GNU C Library; if not, see
# .
# This is the `ldd' command, which lists what shared libraries are
# used by given dynamically-linked executables. It works by invoking the
# run-time dynamic linker as a command and setting the environment
# variable LD_TRACE_LOADED_OBJECTS to a non-empty value.
# We should be able to find the translation right at the beginning.
TEXTDOMAIN=libc
TEXTDOMAINDIR=/usr/share/locale
RTLDLIST="/lib/ld-linux.so.2 /lib64/ld-linux-x86-64.so.2 /libx32/ld-linux-x32.so.2"
warn=
bind_now=
verbose=
while test $# -gt 0; do
case "$1" in
--vers | --versi | --versio | --version)
echo 'ldd (Ubuntu EGLIBC 2.19-0ubuntu6.13) 2.19'
printf $"Copyright (C) %s Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
" "2014"
printf $"Written by %s and %s.
" "Roland McGrath" "Ulrich Drepper"
exit 0
;;
--h | --he | --hel | --help)
echo $"Usage: ldd [OPTION]... FILE...
--help print this help and exit
--version print version information and exit
-d, --data-relocs process data relocations
-r, --function-relocs process data and function relocations
-u, --unused print unused direct dependencies
-v, --verbose print all information
"
printf $"For bug reporting instructions, please see:\\n%s.\\n" \
""
exit 0
;;
-d | --d | --da | --dat | --data | --data- | --data-r | --data-re | \
--data-rel | --data-relo | --data-reloc | --data-relocs)
warn=yes
shift
;;
-r | --f | --fu | --fun | --func | --funct | --functi | --functio | \
--function | --function- | --function-r | --function-re | --function-rel | \
--function-relo | --function-reloc | --function-relocs)
warn=yes
bind_now=yes
shift
;;
-v | --verb | --verbo | --verbos | --verbose)
verbose=yes
shift
;;
-u | --u | --un | --unu | --unus | --unuse | --unused)
unused=yes
shift
;;
--v | --ve | --ver)
echo >&2 $"ldd: option \`$1' is ambiguous"
exit 1
;;
--) # Stop option processing.
shift; break
;;
-*)
echo >&2 'ldd:' $"unrecognized option" "\`$1'"
echo >&2 $"Try \`ldd --help' for more information."
exit 1
;;
*)
break
;;
esac
done
nonelf ()
{
# Maybe extra code for non-ELF binaries.
return 1;
}
add_env="LD_TRACE_LOADED_OBJECTS=1 LD_WARN=$warn LD_BIND_NOW=$bind_now"
add_env="$add_env LD_LIBRARY_VERSION=\$verify_out"
add_env="$add_env LD_VERBOSE=$verbose"
if test "$unused" = yes; then
add_env="$add_env LD_DEBUG=\"$LD_DEBUG${LD_DEBUG:+,}unused\""
fi
# The following command substitution is needed to make ldd work in SELinux
# environments where the RTLD might not have permission to write to the
# terminal. The extra "x" character prevents the shell from trimming trailing
# newlines from command substitution results. This function is defined as a
# subshell compound list (using "(...)") to prevent parameter assignments from
# affecting the calling shell execution environment.
try_trace() (
output=$(eval $add_env '"$@"' 2>&1; rc=$?; printf 'x'; exit $rc)
rc=$?
printf '%s' "${output%x}"
return $rc
)
case $# in
0)
echo >&2 'ldd:' $"missing file arguments"
echo >&2 $"Try \`ldd --help' for more information."
exit 1
;;
1)
single_file=t
;;
*)
single_file=f
;;
esac
result=0
for file do
# We don't list the file name when there is only one.
test $single_file = t || echo "${file}:"
case $file in
*/*) :
;;
*) file=./$file
;;
esac
if test ! -e "$file"; then
echo "ldd: ${file}:" $"No such file or directory" >&2
result=1
elif test ! -f "$file"; then
echo "ldd: ${file}:" $"not regular file" >&2
result=1
elif test -r "$file"; then
RTLD=
ret=1
for rtld in ${RTLDLIST}; do
if test -x $rtld; then
dummy=`$rtld 2>&1`
if test $? = 127; then
verify_out=`${rtld} --verify "$file"`
ret=$?
case $ret in
[02]) RTLD=${rtld}; break;;
esac
fi
fi
done
case $ret in
0|2)
try_trace "$RTLD" "$file" || result=1
;;
1)
# This can be a non-ELF binary or no binary at all.
nonelf "$file" || {
echo $" not a dynamic executable"
result=1
}
;;
*)
echo 'ldd:' ${RTLD} $"exited with unknown exit code" "($ret)" >&2
exit 1
;;
esac
else
echo 'ldd:' $"error: you do not have read permission for" "\`$file'" >&2
result=1
fi
done
exit $result
# Local Variables:
# mode:ksh
# End: