【问题标题】:cross compiler ldd交叉编译器ldd
【发布时间】:2011-09-03 05:56:48
【问题描述】:

我创建了一个交叉编译的 arm 可执行文件。我想找到可执行文件的库依赖项。我正在使用 ubuntu natty 并安装了 arm-linux-gnueabi 工具链,其中不包含 ldd。有没有工具可用于查看 linux 中的 arm 可执行库依赖关系。

【问题讨论】:

    标签: linux ubuntu arm cross-compiling ldd


    【解决方案1】:

    这有点麻烦,但它是我能找到的最好的解决方案,而且它对于基本使用确实非常有效 - 只需将此脚本保存为“arm-none-linux-gnueabi-ldd”与您的其他交叉工具。

    #!/bin/sh
    arm-none-linux-gnueabi-readelf -a $1 | grep "Shared library:"
    

    【讨论】:

    • 即使是我的原生 binutils 的 readelf 也能胜任(原生 objdump 不行)。
    • -a 选项有点矫枉过正,共享库引用都在动态部分,-d 选项。此外,像这样的工具或 objdump 答案是正确的,因为交叉编译器 ldd 无法工作,因为 ldd 的工作方式:它尝试半运行可执行跟踪库加载,这对外国文件不起作用二进制。
    • 抱歉,readelf 无法替换 ldd。请参阅此stackoverflow.com/questions/11524820/…。 readelf -d 输出类似于 objdump。谁能有更好的答案?
    • @longbkit 为了让结果更接近ldd,你必须递归调用readelf
    • 在 Debian 和 Ubuntu 中,读取 ELF 二进制文件的程序名称为 arm-linux-gnueabi-readelf。用“-d”调用它并用greping“共享库:”在我的机器上工作。
    【解决方案2】:

    您也可以使用 objdump 来转储和搜索二进制文件的标头部分。这可能会为您节省几毫秒...

    #!/bin/sh  
    arm-none-linux-gnueabi-objdump -x $1 | grep NEEDED
    

    【讨论】:

    • 在 Debian 和 Ubuntu 中,命令的名称是 arm-linux-gnueabi-objdump
    【解决方案3】:

    这是另一个选项,您可以将 LD_TRACE_LOADED_OBJECTS 环境变量设置为任何值,例如 1,然后您只需运行可执行文件,输出应该是它的动态依赖项。

    【讨论】:

      【解决方案4】:

      我找到了这个,希望它可以帮助很多仍在寻找真正的 ldd 解决方案的人。 ldd 只是一个支持 ld-linux 库的脚本。那么为什么不制作自己的 ldd 脚本呢?首先你需要在你的系统中找到 ld-linux 库,它应该是可用的。就我而言,它是 /lib/ld-linux-armhf.so.3,所以我将它放入 RTLDLIST,如下面的脚本所示。

      把这个脚本放在你的设备或板子里,你就可以拥有 ldd ,它可以非常方便地找到可执行文件的依赖库。

      祝你好运!

      #! /bin/bash
      # Copyright (C) 1996-2011, 2012 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, write to the Free
      # Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
      # 02111-1307 USA.
      
      
      # 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 /lib/ld-linux-armhf.so.3"
      warn=
      bind_now=
      verbose=
      
      while test $# -gt 0; do
        case "$1" in
        --vers | --versi | --versio | --version)
          echo 'ldd (Ubuntu EGLIBC 2.15-0ubuntu10.3) 2.15'
          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.
      " "2012"
          printf $"Written by %s and %s.
      " "Roland McGrath" "Ulrich Drepper"
          exit 0
          ;;
        --h | --he | --hel | --help)
          printf $"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:
      %s.
      " "<http://www.debian.org/Bugs/>"
          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 use of cat is needed to make ldd work in SELinux
      # environments where the executed program might not have permissions
      # to write to the console/tty.  But only bash 3.x supports the pipefail
      # option, and we don't bother to handle the case for older bash versions.
      if x=`set -o` && test "$x" != "${x#*pipefail}" && set -o pipefail ; then
        try_trace() {
          eval $add_env '"$@"' | cat
        }
      else
        try_trace() {
          eval $add_env '"$@"'
        }
      fi
      
      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
          verify_out=`${rtld} --verify "$file"`
          ret=$?
          case $ret in
          [02]) RTLD=${rtld}; break;;
          esac
            fi
          done
          case $ret in
          0|2)
            try_trace "$RTLD" "$file" || result=1
            ;;
          1|126)
            # 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:
      

      【讨论】:

        【解决方案5】:

        我在处理一个项目(涉及在 ARM 上移植一些 C++ 代码)遇到[Sourceware.Bugzilla]: Bug 16628 - Segfault after a binary without pthread dlopen()s a library linked with pthread 时找到了解决方案。

        我正在使用 Ubtu 16.04,对于 ARM 交叉编译工具,我安装了 g++-4.9-arm-linux-gnueabihf(以及依赖项,还强迫我卸载g++-multilib(和依赖项))。为了测试(运行)可执行文件,我安装了QEMU (qemu-user-static)。

        根据[man7]: LDD(1)(这只是一个shell (bash) 脚本):

        在通常情况下,ldd 调用标准动态链接器(请参阅ld.so(8))并将 LD_TRACE_LOADED_OBJECTS 环境变量设置为 1。

        我将以上述错误报告中的数据为例。

        issue16417.cpp

        #include <string>
        #include <iostream>
        
        
        extern char **environ;
        
        
        int main() {
            for (char **it = environ; *it != nullptr; ++it) {
                std::string str(*it);
                std::cout << "export " << str.substr(0, str.find('=')) << std::endl;
            }
        }
        

        build_issue16417.sh(删除了编译器不支持的标志):

        #!/bin/bash
        
        _BUILD_TOOL_BASE_NAME=arm-linux-gnueabihf-g++-4.9
        _FILE_BASE_NAME=issue16417
        
        ${_BUILD_TOOL_BASE_NAME} -pthread -std=gnu++0x -pedantic -ggdb -O2 -pipe -mtls-dialect=gnu2 -ftree-loop-distribution -ftree-vectorize -fmerge-all-constants -fira-loop-pressure -pedantic -c -o ${_FILE_BASE_NAME}.o ${_FILE_BASE_NAME}.cpp
        
        ${_BUILD_TOOL_BASE_NAME} -pthread -std=gnu++0x -pedantic -ggdb -O2 -pipe -mtls-dialect=gnu2 -ftree-loop-distribution -ftree-vectorize -fmerge-all-constants -fira-loop-pressure -pedantic -Wl,-O1 -Wl,--sort-common -Wl,--enable-new-dtags -Wl,--gc-sections -Wl,--hash-style=gnu -o ${_FILE_BASE_NAME}.${_BUILD_TOOL_BASE_NAME} ${_FILE_BASE_NAME}.o  -Wl,--as-needed -pthread -Wl,-fuse-ld=gold
        

        输出

        [cfati@cfati-ubtu16x64-0:~/Work/Dev/StackOverflow/q006150000]> ~/sopr.sh
        *** Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ***
        [prompt]>
        [prompt]> uname -a
        Linux cfati-ubtu16x64-0 4.15.0-39-generic #42~16.04.1-Ubuntu SMP Wed Oct 24 17:09:54 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
        [prompt]> which arm-linux-gnueabihf-g++-4.9
        /usr/bin/arm-linux-gnueabihf-g++-4.9
        [prompt]> ldd /usr/bin/arm-linux-gnueabihf-g++-4.9
                linux-vdso.so.1 =>  (0x00007ffdf55c2000)
                libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f59b6c62000)
                /lib64/ld-linux-x86-64.so.2 (0x00007f59b702c000)
        [prompt]> dpkg -S /usr/bin/arm-linux-gnueabihf-g++-4.9
        g++-4.9-arm-linux-gnueabihf: /usr/bin/arm-linux-gnueabihf-g++-4.9
        [prompt]>
        [prompt]> ls
        build_issue16417_g++4.9.sh  issue16417.cpp
        [prompt]> ./build_issue16417_g++4.9.sh
        [prompt]> ls
        build_issue16417_g++4.9.sh  issue16417.arm-linux-gnueabihf-g++-4.9  issue16417.cpp  issue16417.o
        [prompt]> file ./issue16417.arm-linux-gnueabihf-g++-4.9
        ./issue16417.arm-linux-gnueabihf-g++-4.9: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux-armhf.so.3, for GNU/Linux 3.2.0, BuildID[sha1]=17e0f3d6ceaa13df4ac031e6581074757abee36c, not stripped
        [prompt]> echo ${_QEMU_CMD}
        /usr/bin/qemu-arm-static -L /usr/arm-linux-gnueabihf
        [prompt]> ${_QEMU_CMD} ./issue16417.arm-linux-gnueabihf-g++-4.9
        qemu: uncaught target signal 11 (Segmentation fault) - core dumped
        Segmentation fault (core dumped)
        [prompt]>
        [prompt]> ldd ./issue16417.arm-linux-gnueabihf-g++-4.9
                not a dynamic executable
        

        正如预期的那样,(常规)ldd 不适用于 ARM 二进制文件。

        ldd 脚本的开头某处有一行(没有其他人引用 .sos):

        RTLDLIST="/lib/ld-linux.so.2 /lib64/ld-linux-x86-64.so.2 /libx32/ld-linux-x32.so.2"
        

        正如所见,它没有正确的 ld.so(目前只有 i686x86_64 的),所以它不能处理 ARM 二进制文件。为了使事情顺利进行(请注意,对于每个选项,sudo 都是必需的):

        1. 在行尾添加一个ARM
        2. 创建 ldd 的副本,并修改该版本(将现有 .so 替换为正确的版本)

        我选择了 2nd 变体。但是 ARM ld.so 在哪里呢?您可能已经猜到,它可以从 ${_QEMU_CMD} env var 中获取(毕竟 qemu 也需要它)。在我的机器上它是:/usr/arm-linux-gnueabihf/lib/ld-2.23.so(需要libc6-armhf-cross,但现在应该已经安装了)。所以,我把 ldd 复制到 arm-linux-gnueabihf-ldd 中,并将上面的行替换为:

        _LIB_PATH=/usr/arm-linux-gnueabihf/lib
        
        RTLDLIST="${_LIB_PATH}/ld-2.23.so"
        
        # @TODO - cfati: Not a fan of the line below (I think it's considered bad practice), but without it, it can't find the libraries locations.
        export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${_LIB_PATH}
        

        同时发布 diff 格式(查看[SO]: Run/Debug a Django application's UnitTests from the mouse right click context menu in PyCharm Community Edition? (@CristiFati's answer)修补utrunner部分)了解如何应用它):

        [prompt]> diff --binary -uN /usr/bin/ldd /usr/bin/arm-linux-gnueabihf-ldd
        --- /usr/bin/ldd        2018-01-15 04:49:13.000000000 +0200
        +++ /usr/bin/arm-linux-gnueabihf-ldd    2018-12-04 19:34:19.499001000 +0200
        @@ -26,7 +26,13 @@
         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"
        +_LIB_PATH=/usr/arm-linux-gnueabihf/lib
        +
        +RTLDLIST="${_LIB_PATH}/ld-2.23.so"
        +
        +# @TODO - cfati: Not a fan of the line below (I think it's considered bad practice), but without it, it can't find the libraries locations.
        +export LD_LIBRARY_PATH=${LD_LIBRARY_PATH}:${_LIB_PATH}
        +
         warn=
         bind_now=
         verbose=
        

        尝试在 ARM 可执行文件上运行“newldd,然后

        [prompt]> arm-linux-gnueabihf-ldd ./issue16417.arm-linux-gnueabihf-g++-4.9
                libstdc++.so.6 => /usr/arm-linux-gnueabihf/lib/libstdc++.so.6 (0xf66c6000)
                libc.so.6 => /usr/arm-linux-gnueabihf/lib/libc.so.6 (0xf65da000)
                /lib/ld-linux-armhf.so.3 => /usr/arm-linux-gnueabihf/lib/ld-2.23.so (0xf6fd7000)
                libm.so.6 => /usr/arm-linux-gnueabihf/lib/libm.so.6 (0xf6562000)
                libgcc_s.so.1 => /usr/arm-linux-gnueabihf/lib/libgcc_s.so.1 (0xf6538000)
        

        注意:接下来是不是问题/答案的一部分
        无论如何,在 build_issue16417.sh 中将 --as-needed 替换为 --no-as-needed >,产量:

        [prompt]> vi build_issue16417_g++4.9.sh
        [prompt]> ./build_issue16417_g++4.9.sh
        [prompt]> ${_QEMU_CMD} ./issue16417.arm-linux-gnueabihf-g++-4.9
        export LC_NAME
        export LC_TIME
        export LESSCLOSE
        export XDG_RUNTIME_DIR
        export LESSOPEN
        export SSH_CONNECTION
        export XDG_DATA_DIRS
        export LOGNAME
        export HOME
        export SHLVL
        export PAPERSIZE
        export LC_MEASUREMENT
        export LANG
        export PWD
        export LC_IDENTIFICATION
        export QT_QPA_PLATFORMTHEME
        export PATH
        export MAIL
        export LC_TELEPHONE
        export LS_COLORS
        export USER
        export SSH_TTY
        export OLDPWD
        export LC_NUMERIC
        export SSH_CLIENT
        export SHELL
        export TERM
        export ANDROID_HOME
        export LC_MONETARY
        export XDG_SESSION_ID
        export LC_ADDRESS
        export LC_PAPER
        

        :)

        【讨论】:

        • 我将此标记为有用的参考,以检查目标上正在使用哪些库,您通常只需运行 LD_TRACE_LOADED_OBJECTS=1 app_name,即可显示它正在引用的库(以及任何缺失的库)跨度>
        • @MichaelFirth:我知道 env var(这是答案的一部分),但这是基于加载程序能够处理可执行文件的事实(这里不是这种情况)。
        【解决方案6】:

        如前所述,设计为 ldd can only been executed on target。但是,可以使用readelf 来模仿ldd 的行为。在crosstool-ng 项目中开发了一个名为xldd 的脚本。此脚本的独立版本可在此处获得:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-10-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-02-05
          相关资源
          最近更新 更多