62

在为本机平台开发时,我可以使用 ldd 列出所有共享库(.so 文件),我构建的二进制可执行文件将在启动时尝试加载。但是在交叉编译时,我不知道如何获得相同的信息。这ldd不是一个普通的 binutils 实用程序,如stripor ar,可以与gcc交叉编译一起构建,而是一个神秘的 shell 脚本,显然只能在本机平台上运行。

那么,使用跨目标 binutils 工具,有没有办法获取外部二进制文件的动态链接依赖项列表?

4

8 回答 8

86

有什么方法可以获取外部二进制文件的动态链接依赖项列表

您可以很容易地列出二进制文件的直接依赖项:

readelf -d a.out | grep NEEDED

 0x0000000000000001 (NEEDED)             Shared library: [librt.so.1]
 0x0000000000000001 (NEEDED)             Shared library: [libc.so.6]

我知道没有办法递归地继续这个来获得完整的列表(就像ldd这样)。您必须NEEDED手动为每个库重复该过程。

于 2012-04-07T14:36:22.190 回答
15

你可以做bash -x ldd /bin/ls以了解ldd正在做什么。该ldd脚本并不那么“神秘”。它基本上运行

LD_TRACE_LOADED_OBJECTS=1 /lib64/ld-linux-x86-64.so.2 /bin/ls

所以它使用系统的动态加载器(因为结果ldd取决于您的实际环境和系统!)。但是您可以使用objdump -x /bin/ls可执行文件的动态部分进行检查,例如

% objdump -x /bin/ls
  /bin/ls:     file format elf64-x86-64
  /bin/ls
  architecture: i386:x86-64, flags 0x00000112:
  EXEC_P, HAS_SYMS, D_PAGED
  start address 0x00000000004046d4

  Program Header:
      PHDR off    0x0000000000000040 vaddr 0x0000000000400040 paddr 0x0000000000400040 align 2**3
           filesz 0x00000000000001c0 memsz 0x00000000000001c0 flags r-x
    INTERP off    0x0000000000000200 vaddr 0x0000000000400200 paddr 0x0000000000400200 align 2**0
           filesz 0x000000000000001c memsz 0x000000000000001c flags r--
      LOAD off    0x0000000000000000 vaddr 0x0000000000400000 paddr 0x0000000000400000 align 2**21
           filesz 0x0000000000019ef4 memsz 0x0000000000019ef4 flags r-x
      LOAD off    0x000000000001a000 vaddr 0x000000000061a000 paddr 0x000000000061a000 align 2**21
           filesz 0x000000000000077c memsz 0x0000000000001500 flags rw-
   DYNAMIC off    0x000000000001a028 vaddr 0x000000000061a028 paddr 0x000000000061a028 align 2**3
           filesz 0x00000000000001d0 memsz 0x00000000000001d0 flags rw-
      NOTE off    0x000000000000021c vaddr 0x000000000040021c paddr 0x000000000040021c align 2**2
           filesz 0x0000000000000044 memsz 0x0000000000000044 flags r--
  EH_FRAME off    0x0000000000017768 vaddr 0x0000000000417768 paddr 0x0000000000417768 align 2**2
           filesz 0x00000000000006fc memsz 0x00000000000006fc flags r--
     STACK off    0x0000000000000000 vaddr 0x0000000000000000 paddr 0x0000000000000000 align 2**3
           filesz 0x0000000000000000 memsz 0x0000000000000000 flags rw-

  Dynamic Section:
    NEEDED               libselinux.so.1
    NEEDED               librt.so.1
    NEEDED               libacl.so.1
    NEEDED               libc.so.6
    INIT                 0x0000000000402148
    FINI                 0x00000000004125f8
    HASH                 0x0000000000400260
    GNU_HASH             0x00000000004005c0
    STRTAB               0x0000000000401100
    SYMTAB               0x0000000000400620
    STRSZ                0x00000000000004d7
    SYMENT               0x0000000000000018
    DEBUG                0x0000000000000000
    PLTGOT               0x000000000061a208
    PLTRELSZ             0x0000000000000990
    PLTREL               0x0000000000000007
    JMPREL               0x00000000004017b8
    RELA                 0x0000000000401740
    RELASZ               0x0000000000000078
    RELAENT              0x0000000000000018
    VERNEED              0x00000000004016c0
    VERNEEDNUM           0x0000000000000003
    VERSYM               0x00000000004015d8

  Version References:
    required from librt.so.1:
      0x09691a75 0x00 05 GLIBC_2.2.5
    required from libacl.so.1:
      0x05822452 0x00 06 ACL_1.2
      0x05822450 0x00 04 ACL_1.0
    required from libc.so.6:
      0x09691a75 0x00 03 GLIBC_2.2.5
      0x0d696913 0x00 02 GLIBC_2.3

同样,实际的依赖取决于运行二进制文件的系统(例如,因为我可以在某个地方LD_LIBRARY_PATH拥有自己的libc.so.6,这将是一个坏主意)。

所以你需要一个交叉变体objdump

于 2012-04-07T05:49:40.267 回答
5

而在 中gdb信息共享类似于ldd。它提供了可执行文件的完整人类可读的运行时信息。
readelf错过路径和其他库信息
readelf是对主机学习非常好的工具。开发人员可以选择可行的。

于 2013-04-18T12:50:41.440 回答
3

这对我有帮助

objdump -p /path/to/program | grep NEEDED 
于 2018-01-09T05:46:39.670 回答
2

很抱歉创建了一个僵尸线程,但我正在为我的 OpenWRT 路由器做一些事情,并希望它检查一些依赖关系,看看我的 jffs2 分区上是否有足够的空间来复制e2fsck. 简短的回答:nope.avi

Anyhoo,我制作了一个小脚本,使用接受的答案加上一些(可能过于冗长)grep调用,稍微挥手和一些独角兽眼泪(不用担心,它们是快乐的眼泪!)我设法将以下脚本放在一起,给出你所有的依赖。我确信有很大的改进空间,尤其是 RE:循环和递归,以及它一直都是 bashism(即索引数组)的事实,但这至少名义上对我有用:

#!/bin/bash

declare -a search_path
declare -a found_deps

find_dependencies() {
    local file="$1"
    local -a deps
    local -a deps_to_process

    deps=( $( readelf -d "$file" | grep "NEEDED" | \
        grep -o -E "\[[^]]*\]" | grep -o -E "[^][]*" ) )

    local add_this_dep=true

    # always assume we've found $file and add it to the $found_deps list
    # if it's not there
    for found_dep in "${found_deps[@]}"
    do
        if [ "$found_dep" = "$(basename $file)" ]
        then
            add_this_dep=false
            break
        fi
    done

    # if $add_this_dep is true, go ahead and add to the found_deps list
    if $add_this_dep
    then
        found_deps+=("$(basename $file)")
    fi

    # for every dependency found by readelf (no path)
    for dep in "${deps[@]}"
    do
        local process_dep=true

        # if the basename of the file passed into the function is
        # this dep, skip processing altogether
        if [ "$dep" = "$(basename $file)" ]
        then
            break
        else
            # otherwise, if it's one of the 'found deps' don't process it
            for found_dep in "${found_deps[@]}"
            do
                if [ "$dep" = "$found_dep" ]
                then
                    process_dep=false
                    break
                fi
            done

            # it wasn't one of the 'found deps' so add 
            # it to the found_deps list
            if $process_dep
            then
                found_deps+=($dep)
            fi
        fi

        # if we are supposed to process this dep
        if $process_dep
        then
            local file_path=

            # check each search path for a file named $dep underneath it
            for dir in $search_path
            do
                file_path=$( find "$dir" -name "$dep" | head -n 1 )

                # if the $file_path is not empty, then we found
                # a copy of it, so break out of the loop
                if [ -n "$file_path" ]; then break; fi;
            done

            # if the $file_path is not empty, then we found a copy
            # of the file, place it the list of deps to be processed
            if [ -n "$file_path" ]
            then
                deps_to_process+=($file_path)
            fi
        fi
    done

    # now, go through all of our $deps_to_process (with path)
    # and run "find_dependencies" on them
    for dep_to_process in "${deps_to_process[@]}"
    do
        find_dependencies "$dep_to_process"
    done
}

argc=$#

if [ $argc -eq 0 ]
then
    printf '%s: prints dependencies of a (potentially) non-native elf executable, recursively\n'
    printf '\n'
    printf 'usage:\n'
    printf '\t%s <non-native elf executable> [ --supress-header ] [ <path> ... ]\n' "$(basename $0)"
    printf '\twhere\n'
    printf '\t\t<non-native elf executable> is the name of a file to find the dependencies of.\n'
    printf '\t\t[ <path> ... ] is an optional list of directories under which to search for libraries.\n'
    printf '\t\t[ --supress-header ] is an optional flag that prints nothing other than the list of files to stdout.\n'
    printf '\t\t\t(without the parameter a banner is sent to stderr)'
    printf '\n'
else
    file="$1"
    shift 1

    show_header=true

    if [ "$1" = "--supress-header" ]; then show_header=false; shift 1; fi;

    if $show_header
    then
        printf ' -------------------------------------------------------------------------------------------------------------\n' 1>&2
        printf '  ldd-nonnative: find all dependencies of a (potentially) non-native binary %s\n' "$file" 1>&2
        printf ' -------------------------------------------------------------------------------------------------------------\n' 1>&2
    fi

    search_path="$@"
    find_dependencies $file

    printf '\t%s\n' "${found_deps[@]}"
fi

# ❤ copyheart, shelleybutterfly, 2014
# love is never subject to the low; please copy and share with love :)

# contact information:
# shelleybutterfly@mojoprocode.com

# I hereby dedicate this software to the public domain in all jurisdictions
# where possible. In other jurisdictions, I license it to you under your
# choice of permissive license, as defined by the Open Source Institute (OSI),
# found at URL http://opensource.org. Should such a license be unavailable in
# your jurisdiection, you may use any copyleft open source license, again as
# defined by OSI; and if that too is unavailable, then you are licensed this
# software under the least restrictive possible terms allowed in your
# jurisdiction.

# I request but do not require that you give credit to me, shelleybutterfly,
# which I will accept in cases of licensing other than the public domain as
# valuable consideration for your use of my software. (I love to know that 
# my name is plastered all over some obscure piece of code that's at least
# appreciated by those who do see it, and I consider that more than enough
# consideration. :D) This software is provided completely as-is, and I take
# absolutely no responsibility for any damages that it may cause. It has
# not been fully tested and should be considered pre-alpha release quality,
# (that is to say, it is likely unstable and unsafe to use without your own
# validation to ensure that it meets some or any your needs without: among
# other things: melting your computer, calling your grandma at midnight,
# telling your girlfriend she's fat, and throwing your computer in the
# dishwasher to make sure it's clean, and you take full responsibility for
# doing your own testing to ensure that it suits your needs, and operates 
# properly int the conditions under which you intend to use it.

# Should you not be willing to take this risk, it is highly recommended
# that you do not use this software at all, ever, and that you instead find
# a real commercial piece of software, or other warranted piece of software,
# as I can not and do not and shall not provide any warranty of fitness for
# any purpose whatsoever, even to scrub your toilet, and it's provided with
# the understanding that it will be used primarily as an educational tool
# rather than any sort of production code. I disclaim any responsibility for
# anything that may happen to you due to your use of software, even if it
# causes huge zits, a rash under your boobs that wont go away, or a burning
# sensation when you pee. Sorry, **especially** for a burning sensation when
# you pee.

# Your use of this software implies acceptance of these terms as well as 
# any painful urination or other issues it may cause in your life.

# [deep breath] 

# my love to you all; I hope this software was useful to you in some way; if
# you end up using it despite the dire warnings against doing so, feel free
# to drop me a note at shelleybutterfly@mojoprocode.com, as I imagine it
# will be rare enough to make my day, every time. ♥

所以,你去吧。希望它可以帮助某人。Egads 我花了很长时间才得到足够好的 shell 脚本能够完成这样的事情,更不用说我花费的时间比它应该花费的时间要长得多,所以请原谅可能动摇了你们中的一些人脚本大师是你存在的核心。:)

于 2014-03-23T07:00:57.207 回答
1

这个添加有点晚了,但有人可能会受益/澄清。readelf 的 -A 标志不是给出与 ldd 相同的结果吗?

    $ readelf -AW /bin/vi

Library list section '.gnu.liblist' contains 8 entries:
     Library              Time Stamp          Checksum   Version Flags
  0: libselinux.so.1      2011-07-25T08:02:58 0x17a7d5f7 0       0
  1: libtermcap.so.2      2011-07-25T08:02:59 0x29ae9ff7 0       0
  2: libacl.so.1          2011-07-25T08:02:58 0x60748842 0       0
  3: libc.so.6            2011-07-25T08:02:58 0x0c2c7eeb 0       0
  4: libdl.so.2           2011-07-25T08:02:58 0xdfbfc467 0       0
  5: libsepol.so.1        2011-07-25T08:02:58 0x857499cb 0       0
  6: /lib64/ld-linux-x86-64.so.2 2011-07-25T08:02:58 0x9e6549b7 0       0
  7: libattr.so.1         2011-07-25T08:02:58 0x862f1546 0       0

这里唯一缺少的信息似乎是这些库所在的完整路径。

另一方面,到目前为止提到的工具只有在您安装了已知可以工作的情况下才有用。我最常见的问题是:

  1. 安装一个程序(主要通过 rpm),然后在启动过程中无法启动或崩溃。不知何故,我认为这与库不兼容有关,但我还没有找到一种简单的方法来在安装程序之前检查这些东西(实际上也不是之后)
  2. 为了克服(1),有时我会下载源代码并在本地编译。典型的配置脚本部分有用,因为它会告诉您缺少哪些库。但是,它无法告诉您需要哪些最低版本的此类库

任何人都可以对这些问题有所了解吗?顺便说一句,我已经尝试阅读安装说明和发行说明,但它们几乎总是远远不够。

一个强大的示例可能会将所有内容置于上下文中,因此请尝试编译Cinelerra

于 2014-03-24T09:22:45.973 回答
1

按照设计 ldd 只能在目标上执行。但是,可以使用 readelf 模拟 ldd 行为。在 crosstool-ng 项目中开发了一个名为“xldd”的脚本。此脚本的独立版本可在此处获得:

https://gist.github.com/jerome-pouiller/c403786c1394f53f44a3b61214489e6f

于 2016-11-17T16:25:15.860 回答
0

要列出非本机二进制文件的共享库依赖项,您可以尝试以下工具: http: //www.mathembedded.com/component/k2/item/1-cross-ldd.html

我在 SH4 和 MIPS 上使用它。正如其他答案中所报告的那样,您可以使用 readelf 输出和递归循环来实现相同的目标,但由于 cross-ldd 存在,我从来没有自己尝试过。

于 2012-04-09T07:53:43.147 回答