cross compiler ldd

LinuxUbuntuArmCross CompilingLdd

Linux Problem Overview


I have created a cross compiled arm executable. I want to find the library dependency of the executable. I am using ubuntu natty and installed arm-linux-gnueabi tool chain, which does not contain ldd. Is there a tool available to view arm executables library dependancy in linux.

Linux Solutions


Solution 1 - Linux

This is a bit of a kluge, but it's the best solution I could find, and it really works quite well for basic use - just save this script as "arm-none-linux-gnueabi-ldd" with your other cross tools.

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

Solution 2 - Linux

You could also use objdump and in order to just dump and search the header fraction of the binary. This may save you some milliseconds...

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

Solution 3 - Linux

Here is another option, you can set LD_TRACE_LOADED_OBJECTS environment variable to any value, say 1, and then you just run the executable, the output should be its dynamic dependencies.

Solution 4 - Linux

I found this and hope it can help a lot of people who are still searching for a true ldd solution. ldd is just a script with support of ld-linux library. So why not making your own ldd script? First you need to find ld-linux library in your system, which should be available. In my case it is /lib/ld-linux-armhf.so.3 so I put this into RTLDLIST as you can see in the script below.

And put this script in your device or board and you can have ldd which is very convenient to find dependents libraries for an executable.

Good luck!

#! /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:

Solution 5 - Linux

I found a solution when running into [Sourceware.Bugzilla]: Bug 16628 - Segfault after a binary without pthread dlopen()s a library linked with pthread while working on a project (which involved porting some C++ code on ARM).

I'm using Ubtu 16.04, and for ARM cross compile tools I installed g++-4.9-arm-linux-gnueabihf (and dependencies, and also forced me to uninstall g++-multilib (and dependencies)). For testing (running) the executables, I installed QEMU (qemu-user-static).

According to [man7]: LDD(1) (which is just a shell (bash) script):

> In the usual case, ldd invokes the standard dynamic linker (see ld.so(8)) with the LD_TRACE_LOADED_OBJECTS environment variable set to 1.

I'm going to exemplify on the data from the above bug report.

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 (removed flags unsupported by the compiler):

#!/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

Output:

> [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 #4216.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

As expected, (regular) ldd doesn't work for ARM binaries.

In the ldd script, there's a line (no other one references .sos) somewhere at the beginning:

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

As seen, it doesn't have the correct ld.so (so far there are only the i686 and x86_64 ones), so it can't handle ARM binaries. To make things work, either (note that for each option, sudo is required):

  1. Add the ARM one at the end of the line
  2. Create a copy of ldd, and modify that version (replace existing .sos with the right one)

I chose the 2nd variant. But where is ARM ld.so? As you probably guessed, it can be obtained from ${_QEMU_CMD} env var (after all, qemu needs it as well). On my machine it's: /usr/arm-linux-gnueabihf/lib/ld-2.23.so (libc6-armhf-cross required, but that should be installed by now). So, I copied ldd to arm-linux-gnueabihf-ldd, and replaced the above line with:

_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}

Also posting the diff format (check [SO]: Run/Debug a Django application's UnitTests from the mouse right click context menu in PyCharm Community Edition? (@CristiFati's answer) (Patching utrunner section) for how to apply it):

> [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=

Try running the "new" ldd on the ARM executable, and voilĂ :

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

Note: What comes next, is not part of the question / answer.
Anyway, replacing --as-needed by *--**no-*as-needed in build_issue16417.sh, yields:

> [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

:)

Solution 6 - Linux

As already said, by design ldd can only been executed on target. However, it is possible to mimic ldd behavior using readelf. A script called xldd was developed in crosstool-ng project. An independent version of this script is available here:

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

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionTalespin_KitView Question on Stackoverflow
Solution 1 - LinuxstegreView Answer on Stackoverflow
Solution 2 - LinuxMausView Answer on Stackoverflow
Solution 3 - Linuxuser6754418View Answer on Stackoverflow
Solution 4 - LinuxlongbkitView Answer on Stackoverflow
Solution 5 - LinuxCristiFatiView Answer on Stackoverflow
Solution 6 - LinuxJérôme PouillerView Answer on Stackoverflow