查看可执行程序(ELF)或动态库所依赖动态库——ldd脚本分析

1.序

搞清可执行程序(动态库)所依赖的动态库信息是非常有帮助的。

2.查看方法

系统信息:

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

2.1 使用 ldd

# 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)

2.2 使用 readelf -d

# 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。 该虚拟库为用户程序以处理器可支持的最快的方式 (对于特定处理器,采用中断方式;对于大多数最新的处理器,采用快速系统调用方式) 访问系统函数提供了必要的逻辑 。

3. ldd脚本

脚本信息:

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:

你可能感兴趣的:(编译器,Linux,命令,脚本,库,linux)